При рефакторинге моего первого ответа я понял, что у панд очень хорошая обработка данных временных рядов.Вы можете прочитать здесь об этом.Кроме того, группирование данных с помощью groupby
кажется довольно эффективным и не создает лишних копий данных, как я изначально думал.
Ответ A масштабируется намного лучше (линейно) с размером набора данных, чем ответ B. Я мог бывычислить случай 20k примерно за 100 мс (измеренный с %timeit
в ipython
).Ниже приведен отрывок данных, с которыми я тестировал.
Ответ A:
Этот подход группирует данные по минутам, а затем применяет фильтр скользящих средних по группам.Прочитайте здесь о оконных функциях в пандах.Список доступных псевдонимов смещения для указания дельт времени приведен здесь .
def assign_rolling_average(x, dt):
x.cumm_vol_LB = x.cumm_vol.rolling(window=dt).mean()
return x
dt='3D' # width of rolling average window: 3 days
# Group data by the time.
g = df.groupby(lambda x: x.time())
# Apply the moving average filter on all groups.
df = g.apply(assign_rolling_average, dt=dt)
Ответ B (намного медленнее):
Это был мой первоначальный ответ,Он вручную определяет строки для работы.Он включает в себя несколько операций с полноразмерными логическими индексами и, вероятно, страдает от проблем с локальностью данных .Он масштабируется во время выполнения в квадрате с размером проблемы.
from datetime import timedelta
# Time delta: fix here the width of the time window
dt = timedelta(days=3)
# Iterate over the rows
for idx in df.index:
date, time = idx.date(), idx.time()
mask = ((df.index.time == time) # Same time of the day
& (df.index.date <= date) # Not later than today
& (df.index.date >= (date-dt))) # Not older than (today - dt)
df.loc[idx, 'cumm_vol_LB'] = df.loc[mask, 'cumm_vol'].mean()
Это тот кадр данных, с которым я тестировал:
import pandas as pd
df = pd.DataFrame([["2018-01-01 09:15:00", 93228, 0],
["2018-01-01 09:16:00", 124353, 0],
["2018-01-01 09:17:00", 184578, 0],
["2018-01-01 09:18:00", 237003, 0],
["2018-01-01 09:19:00", 264303, 0],
["2018-01-01 09:20:00", 310503, 0],
["2018-01-02 09:15:00", 170928, 0],
["2018-01-02 09:16:00", 261528, 0],
["2018-01-02 09:17:00", 358653, 0],
["2018-01-02 09:18:00", 438678, 0],
["2018-01-02 09:19:00", 559503, 0],
["2018-01-02 09:20:00", 626178, 0],
["2018-01-03 09:15:00", 175953, 0],
["2018-01-03 09:16:00", 294078, 0],
["2018-01-03 09:17:00", 395853, 0],
["2018-01-03 09:18:00", 447078, 0],
["2018-01-03 09:19:00", 486903, 0],
["2018-01-03 09:20:00", 523578, 0],
["2018-01-04 09:15:00", 82727, 0],
["2018-01-04 09:16:00", 129077, 0],
["2018-01-04 09:17:00", 162752, 0],
["2018-01-04 09:18:00", 194852, 0],
["2018-01-04 09:19:00", 239027, 0],
["2018-01-04 09:20:00", 291677, 0]],
columns = ['datetime', 'cumm_vol', 'cumm_vol_LB']
)
df = df.set_index('datetime')
df.index = pd.to_datetime(df.index)