在 groupby 之后采用滚动前求和的更快方法?

Faster way to take rolling forward sum after groupby?

我正在尝试获取每天前 n 分钟 return 的股票,给定一个数据框,其中的行在某些时间间隔对应于 returns。

我试过使用 dask 和多线程对每个组进行滚动计算,但这似乎是我能想到的最快的方法。然而,对于大型数据框(数百万行)(252 天和 1000 只股票),执行此步骤最多需要 40 分钟。

ret_df.sort_values(['date','time','stock'], ascending=False, inplace=True)
gb = ret_df.groupby(['date','stock'])
forward_sum_df = gb.rolling(4, on='time', min_periods = 0)['interval_return'].sum().reset_index()

这将 return 数据框中每一行的接下来 4 次(按日期和股票)的总和,正如预期的那样,但速度很慢。感谢您的帮助!

编辑:添加示例以阐明

          date    stock            time      interval_ret
0   2017-01-03  10000001    09:30:00.000000   0.001418
1   2017-01-03  10000001    09:40:00.000000   0.000000
2   2017-01-03  10000001    09:50:00.000000   0.000000
3   2017-01-03  10000001    10:00:00.000000  -0.000474
4   2017-01-03  10000001    10:10:00.000000  -0.001417
5   2017-01-03  10000001    10:20:00.000000  -0.000944
6   2017-01-03  10000001    10:30:00.000000   0.000000
7   2017-01-03  10000001    10:40:00.000000   0.000000
8   2017-01-03  10000001    10:50:00.000000   0.000000
9   2017-01-03  10000001    11:00:00.000000  -0.000472

以此类推库存 10000002...和日期 2017-01-04....

例如,如果我的持有时间是 30 分钟而不是 10 分钟,我想总结 3 行 'interval_ret',按日期和股票分组。例如:

        date      stock            time           interval_ret_30
0   2017-01-03  10000001    09:30:00.000000   0.001418
1   2017-01-03  10000001    09:40:00.000000   0.000000 - 0.000474
2   2017-01-03  10000001    09:50:00.000000   0.000000 - 0.000474 - 0.001417
3   2017-01-03  10000001    10:00:00.000000  -0.000474 - 0.001417 - 0.000944
4   2017-01-03  10000001    10:10:00.000000  -0.001417 - 0.000944
5   2017-01-03  10000001    10:20:00.000000  -0.000944
6   2017-01-03  10000001    10:30:00.000000   0.000000
7   2017-01-03  10000001    10:40:00.000000  -0.000472
8   2017-01-03  10000001    10:50:00.000000  -0.000472
9   2017-01-03  10000001    11:00:00.000000  -0.000472

我不知道你是否可以将其适应 pandas,但你可以使用 numpy 在不到一秒的时间内获得 2000 万个值的滚动累积和:

N         = 20000000
stocks    = (np.random.random(N)*100)
window    = 4
cumStocks = np.cumsum(np.append(stocks,np.zeros(window)))
rollSum   = cumStocks[window:] - cumStocks[:-window]

诀窍是计算整个数组的累积和,然后用与 window 的大小相对应的偏移量从自身中减去结果数组。

cumsum 源数组用零填充以保持原始大小。比 window 大小更接近数组末尾的最后几个元素将仅获得剩余值的滚动总和。如果你不需要这些 "incomplete" 和,你可以简单地使用 cumStocks = np.cumsum(stocks) 并且计算将能够在一秒钟内完成 1 亿个值。

有人似乎在这里使用 pandas 找到了解决此问题的方法:

df.groupby(level=0).cumsum() - df.groupby(level=0).cumsum().shift(5)