在一般情況下,如果日期是完全隨意的,我想你將不得不在行或use df.apply
,使用Python的for-loop
(其中引擎蓋下,還使用了Python的循環。)
然而,如果您的日期與上述情況共用同一頻率,則應該比使用df.apply
快得多:根據常見頻率擴展時間序列 - 在這種情況下爲1分鐘 - 填寫NaNs用零點,然後撥打rolling_sum
:
In [279]: pd.rolling_sum(df.set_index(['Date']).asfreq('1T').fillna(0), window=5, min_periods=1).reindex(df['Date'])
Out[279]:
A
Date
2014-11-21 11:00:00 1
2014-11-21 11:03:00 5
2014-11-21 11:04:00 6
2014-11-21 11:05:00 7
2014-11-21 11:07:00 11
2014-11-21 11:08:00 8
2014-11-21 11:12:00 2
2014-11-21 11:13:00 3
當然,如果您願意接受足夠小的粒度,則任何時間序列都有一個共同的頻率,但所需的尺寸df.asfreq(...)
可能會使此技巧不切實際。
以下是使用df.apply
的更一般方法的示例。請注意,致電searchsorted
依賴df['Date']
排序。
import numpy as np
import pandas as pd
df = pd.read_csv('data', parse_dates=[0], sep=',\s*')
start_dates = df['Date'] - pd.Timedelta(minutes=5)
df['start_index'] = df['Date'].values.searchsorted(start_dates, side='right')
df['end_index'] = np.arange(len(df))
def sum_window(row):
return df['A'].iloc[row['start_index']:row['end_index']+1].sum()
df['rolling_sum'] = df.apply(sum_window, axis=1)
print(df[['Date', 'A', 'rolling_sum']])
產生
Date A rolling_sum
0 2014-11-21 11:00:00 1 1
1 2014-11-21 11:03:00 4 5
2 2014-11-21 11:04:00 1 6
3 2014-11-21 11:05:00 2 7
4 2014-11-21 11:07:00 4 11
5 2014-11-21 11:08:00 1 8
6 2014-11-21 11:12:00 1 2
7 2014-11-21 11:13:00 2 3
這裏是df.asfreq
招比較與調用df.apply
基準:
import numpy as np
import pandas as pd
df = pd.read_csv('data', parse_dates=[0], sep=',\s*')
def big_df(df):
df = df.copy()
for i in range(7):
dates = df['Date'] + pd.Timedelta(df.iloc[-1]['Date']-df.iloc[0]['Date']) + pd.Timedelta('1 minute')
df2 = pd.DataFrame({'Date': dates, 'A': df['A']})
df = pd.concat([df, df2])
df = df.reset_index(drop=True)
return df
def using_apply():
start_dates = df['Date'] - pd.Timedelta(minutes=5)
df['start_index'] = df['Date'].values.searchsorted(start_dates, side='right')
df['end_index'] = np.arange(len(df))
def sum_window(row):
return df['A'].iloc[row['start_index']:row['end_index']+1].sum()
df['rolling_sum'] = df.apply(sum_window, axis=1)
return df[['Date', 'rolling_sum']]
def using_asfreq():
result = (pd.rolling_sum(
df.set_index(['Date']).asfreq('1T').fillna(0),
window=5, min_periods=1).reindex(df['Date']))
return result
In [364]: df = big_df(df)
In [367]: %timeit using_asfreq()
1000 loops, best of 3: 1.21 ms per loop
In [368]: %timeit using_apply()
1 loops, best of 3: 208 ms per loop
非常感謝您的快速回答。我不能使用df.asfreq(...)方法,因爲我的數據集中的最小粒度是秒,而且有數百萬行。但是df.apply方法可以解決這個問題。 – 2014-11-24 09:07:19
一般的方法是有效的,如果在長代碼中使用它,只需記住一件事:函數'sum_window'沒有明確使用輸入'df',所以需要小心。 – nilesh 2017-06-09 05:07:47