Reputation: 784
I've written some code to find how close the diffs of two time series are to each other and do this by finding the distance from the expected difference locations from the nearest actual change and assigning a score based on how far off it is.
In that code I have something that looks like this:
nearest_change = np.abs(actual_changes[actual_changes == change].index - time).min()
minutes_off = nearest_change.seconds/60
if minutes_off < 15:
sum += 1
elif minutes_off < 30:
sum += .8
elif minutes_off < 45:
sum += .6
elif minutes_off < 60:
sum += .4
elif minutes_off < 65:
sum += .2
return sum / count
Is there a more pythonic and concise way to achieve this sort of scoring?
Upvotes: 0
Views: 377
Reputation: 66
You can loop through each threshold and increment by 0.2 each time.
thresholds = [15, 30, 45, 60, 65]
for time_diff in thresholds:
if minutes_off < time_diff:
sum += .2
else:
break
Depending on how many you need, dynamically creating the threshold list might be worth it or not.
Upvotes: 1
Reputation: 41168
If your mappings are discrete and can't be described by a simple formula then you could create them with an OrderedDict
:
from collections import OrderedDict
d = OrderedDict([(15,1),(30,.8),(45,.6),(60,.4),(65,.2)])
for key,value in d.items():
if minutes_off < key:
s += value
break
Note, I renamed sum
, as s
to avoid clash with Python built-in function.
Upvotes: 1
Reputation: 1496
Yes, there is. I'd guess this one is better, although it uses more code to archieve the same effect and is slower. But it does avoid repetition.
class ScoreAccessDict(dict):
def __init__(self, *args, f, **kwargs):
self.f = f
super().__init__(*args, **kwargs)
def __getitem__(self, item):
iterator = iter(self.keys())
try:
best = next(iterator)
except StopIteration:
raise KeyError(item)
for k in iterator:
if self.f(best, item) < self.f(k, item):
best = k
return super().__getitem__(best)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
and to use it:
nearest_change = np.abs(actual_changes[actual_changes == change].index - time).min()
minutes_off = nearest_change.seconds / 60 # spaces between operands and the operator
d = ScoreAccessDict({15: 1, 30: 0.8, 45: 0.6, 60: 0.4, 65: 0.2, float('inf'): 0}, f = lambda x, y: x if x < y else -x)
return s + d[minutes_off] # sum shouldn't be shadowed
But judging from your code, the values added should be calculated using a continuous function anyway. And that would be the most pythonic way.
Upvotes: 0