我正在尝试使用pandas.DataFrame.rolling实现以下目的:

在索引i处,我希望使用sum窗口为最后的mean值滚动mediansize_winparzen,...。仅考虑过去的值(即索引<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))


快得多。不如内置功能快,但足够快。

09-08 04:53