Если вы ищете другие интересные способы решения проблемы, вот ответ, используя itertools :
import datetime as dt
from collections import deque
from itertools import tee, islice, izip
def dayiter(start, end):
one = dt.timedelta(days=1)
day = start
while day <= end:
yield day
day += one
def moving_average(mapping, window, dft=0):
n = float(window)
t1, t2 = tee(dayiter(min(mapping), max(mapping)))
s = sum(mapping.get(day, dft) for day in islice(t2, window))
yield s / n
for olddate, newdate in izip(t1, t2):
oldvalue = mapping.get(olddate, dft)
newvalue = mapping.get(newdate, dft)
s += newvalue - oldvalue
yield s / n
example = {dt.datetime(2008, 1, 1) : 5, dt.datetime(2008, 1, 2) : 6, dt.datetime(2008, 1, 3) : 7, dt.datetime(2008, 1, 4) : 9, dt.datetime(2008, 1, 5) : 12,
dt.datetime(2008, 1, 6) : 15, dt.datetime(2008, 1, 7) : 20, dt.datetime(2008, 1, 8) : 22, dt.datetime(2008, 1, 9) : 25, dt.datetime(2008, 1, 10) : 35}
for ma in moving_average(example, window=3):
print ma
Идеи включают в себя:
Используйте простой генератор, чтобы сделать итератор даты, который циклически повторяется в течение последовательных дней от самого низкого до самого высокого.
Используйте itertools.tee длясоздайте пару итераторов для самых старых данных и самых новых данных (передняя часть окна данных и задняя часть).
Храните промежуточную сумму в переменной s .На каждой итерации обновляйте s , вычитая самое старое значение и добавляя самое новое значение.
Это решение экономит пространство (оно сохраняет не более окна значений в памяти), и это экономит время, одно сложение и одно вычитание для каждого дня независимо от размера окна.
Обработка пропущенных дней по умолчанию на ноль.Существуют и другие стратегии, которые можно использовать для пропущенных дней (например, использование текущей скользящей средней по умолчанию или настройка n вверх и вниз, чтобы отразить количество фактических точек данных в окне).