Средняя временная дельта в списке

Я хочу рассчитать среднюю временную дельту между датами в списке. Хотя следующее работает хорошо, мне интересно, есть ли более разумный способ?

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)

person shinn    schedule 01.09.2010    source источник
comment
добавление еще одного 0 в конец 8640 было бы хорошим началом;)   -  person aaronasterling    schedule 01.09.2010
comment
Почему бы не увеличить скорость вращения Земли? ... Думаю, ты прав =)   -  person shinn    schedule 01.09.2010


Ответы (2)


Кстати, если у вас есть список timedeltas или datetimes, зачем вы вообще занимаетесь математикой?

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)
person Jochen Ritzel    schedule 01.09.2010
comment
+1 Потому что ни ОП, ни я не знали, что это возможно. Дерьмо с датой и временем еще более скучно, чем строки;) - person aaronasterling; 01.09.2010
comment
Я воспользуюсь вашим способом, чтобы рассчитать среднее значение, и ааронстерлингом, чтобы получить дельты. Спасибо =) - person shinn; 01.09.2010
comment
Перебирать индексы не очень питонично. Я бы пошел с: [a - b for a, b in zip(datetimes[:-1], datetimes[1:])] - person abukaj; 06.03.2017
comment
В этом примере это должно быть datetimes[i]-datetimes[i-1] - person sachleen; 01.09.2017

Попробуй это:

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)

На мой взгляд, делать это так более читабельно. Комментарий для менее склонных к математике читателей вашего кода может помочь объяснить, как вы вычисляете каждую дельту. Что бы это ни стоило, одно выражение генератора имеет наименьшее (и я думаю, наименее медленное) инструкции кода операции из всего, на что я смотрел.

  # 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

В частности, отбрасывание лямбды позволяет избежать замыкания, построения кортежа и загрузки двух замыканий. В любом случае вызываются пять функций. Конечно, такая забота о производительности смешна, но приятно знать, что происходит под капотом. Самое главное — это читабельность, и я думаю, что такой подход также дает высокие оценки.

person aaronasterling    schedule 01.09.2010
comment
Да, так намного лучше. Спасибо! - person shinn; 01.09.2010
comment
@shinn, если вы примете ответ THC4k, я могу удалить этот. - person aaronasterling; 01.09.2010
comment
Вы не должны удалять его. Мне нравится способ с izip. - person shinn; 01.09.2010
comment
Отступы не совпадают! ;) - person abukaj; 06.03.2017