我正在尝试使用pandas.DataFrame.rolling
实现以下目的:
在索引i
处,我希望使用sum
窗口为最后的mean
值滚动median
,size_win
,parzen
,...。仅考虑过去的值(即索引<i
)而不考虑将来的值(这是“我们在时间i
时拥有什么信息?”的情况)至关重要。第二个约束是:我想要一个单面的parzen
窗口,即索引i
的值应获得最大权重,i-1
的权重应较小,i-2
的权重应较小,…,i-size_win
的最小值重量。
使用标准df.rolling(window=size_win, win_type='parzen').sum()
不适用于我,因为它将赋予索引i
最小重量和i-(size_win/2)
最大重量。提供center
参数将为索引i
提供最大权重,但也将使用将来的>i
值进行计算。
我找到了使用pandas.DataFrame.rolling(...).apply
的解决方案,但这(当然)非常慢。
请参见以下示例:
import time
import pandas as pd
import scipy as sp
import numpy as np
df = pd.DataFrame(np.random.randint(0,100,size=(100000, 4)), columns=list('ABCD'))
size_win = 1000
def window_single_sided_parzen(window_size):
return sp.signal.parzen((window_size-1)*2+1)[0:window_size]
def custom_rolling_sum(x, window):
return (x * window).sum()
t_start = time.time()
df_rolled_fast = df.rolling(window=size_win, win_type='parzen').sum()
print(f'Run time of builtin: {time.time() - t_start:.2f} s')
t_start = time.time()
df_rolled = df.rolling(window=size_win).apply(lambda x: custom_rolling_sum(x, window_single_sided_parzen(size_win)))
print(f'Run time of apply: {time.time() - t_start:.2f} s')
在我的情况下,内置滚动花费1.3 s(不产生我想要的结果),而我自己的解决方案花费54 s。
任何想法如何更有效地解决这个问题?
最佳答案
发现我在推理中的错误:
df_rolled = df.rolling(window=size_win).apply(lambda x: custom_rolling_sum(x, window_single_sided_parzen(size_win)))
我天真地想,它只会调用昂贵的函数
window_single_sided_parzen(size_win)
一次。实际上,每一行都需要调用它。切换到win = window_single_sided_parzen(size_win)
df_rolled = df.rolling(window=size_win).apply(lambda x: custom_rolling_sum(x, win))
快得多。不如内置功能快,但足够快。