Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Average timedelta in list

Tags:

I want to calculate the avarage timedelta between dates in a list. Although the following works well, I'm wondering if there's a smarter way?

delta = lambda last, next: (next - last).seconds + (next - last).days * 86400    total = sum(delta(items[i-1], items[i]) for i in range(1, len(items))) average = total / (len(items) - 1) 
like image 710
shinn Avatar asked Sep 01 '10 10:09

shinn


People also ask

What does Timedelta mean?

Timedeltas are differences in times, expressed in difference units, e.g. days, hours, minutes, seconds. They can be both positive and negative. Timedelta is a subclass of datetime.

What is the use of Timedelta () function in Python?

timedelta() function. Python timedelta() function is present under datetime library which is generally used for calculating differences in dates and also can be used for date manipulations in Python. It is one of the easiest ways to perform date manipulations.

How do you convert Timedelta to seconds?

To get the Total seconds in the duration from the Timedelta object, use the timedelta. total_seconds() method.


2 Answers

Btw, if you have a list of timedeltas or datetimes, why do you even do any math yourself?

datetimes = [ ... ]  # subtracting datetimes gives timedeltas timedeltas = [datetimes[i-1]-datetimes[i] for i in range(1, len(datetimes))]  # giving datetime.timedelta(0) as the start value makes sum work on tds  average_timedelta = sum(timedeltas, datetime.timedelta(0)) / len(timedeltas) 
like image 77
Jochen Ritzel Avatar answered Oct 03 '22 23:10

Jochen Ritzel


Try this:

from itertools import izip  def average(items):        total = sum((next - last).seconds + (next - last).days * 86400                 for next, last in izip(items[1:], items))      return total / (len(items) - 1) 

In my opinion doing it like this is more readable. A comment for less mathematically inclined readers of your code might help to explain how your are calculating each delta. For what it's worth, one generator expression has the least (and I think least slow) opcode instructions of anything I looked at.

  # The way in your question compiles to....   3           0 LOAD_CONST               1 (<code object <lambda> at 0xb7760ec0, file   "scratch.py", line 3>)               3 MAKE_FUNCTION            0               6 STORE_DEREF              1 (delta)    4           9 LOAD_GLOBAL              0 (sum)              12 LOAD_CLOSURE             0 (items)              15 LOAD_CLOSURE             1 (delta)              18 BUILD_TUPLE              2              21 LOAD_CONST               2 (<code object <genexpr> at 0xb77c0a40, file "scratch.py", line 4>)              24 MAKE_CLOSURE             0              27 LOAD_GLOBAL              1 (range)              30 LOAD_CONST               3 (1)              33 LOAD_GLOBAL              2 (len)              36 LOAD_DEREF               0 (items)              39 CALL_FUNCTION            1              42 CALL_FUNCTION            2              45 GET_ITER                          46 CALL_FUNCTION            1              49 CALL_FUNCTION            1              52 STORE_FAST               1 (total)    5          55 LOAD_FAST                1 (total)              58 LOAD_GLOBAL              2 (len)              61 LOAD_DEREF               0 (items)              64 CALL_FUNCTION            1              67 LOAD_CONST               3 (1)              70 BINARY_SUBTRACT                   71 BINARY_DIVIDE                     72 STORE_FAST               2 (average)              75 LOAD_CONST               0 (None)              78 RETURN_VALUE         None # #doing it with just one generator expression and itertools...    4           0 LOAD_GLOBAL              0 (sum)               3 LOAD_CONST               1 (<code object <genexpr> at 0xb777eec0, file "scratch.py", line 4>)               6 MAKE_FUNCTION            0    5           9 LOAD_GLOBAL              1 (izip)              12 LOAD_FAST                0 (items)              15 LOAD_CONST               2 (1)              18 SLICE+1                           19 LOAD_FAST                0 (items)              22 CALL_FUNCTION            2              25 GET_ITER                          26 CALL_FUNCTION            1              29 CALL_FUNCTION            1              32 STORE_FAST               1 (total)    6          35 LOAD_FAST                1 (total)              38 LOAD_GLOBAL              2 (len)              41 LOAD_FAST                0 (items)              44 CALL_FUNCTION            1              47 LOAD_CONST               2 (1)              50 BINARY_SUBTRACT                   51 BINARY_DIVIDE                     52 RETURN_VALUE         None 

In particular, dropping the lambda allows us to avoid making a closure, building a tuple and loading two closures. Five functions get called either way. Of course this sort of concern with performance is sort of ridiculous but it is nice to know what's going on under the hood. The most important thing is readability and I think that doing it this way scores high on that as well.

like image 20
aaronasterling Avatar answered Oct 03 '22 22:10

aaronasterling