【问题标题】:Faster way to take rolling forward sum after groupby?在 groupby 之后获得滚动总和的更快方法?
【发布时间】:2019-11-14 05:32:07
【问题描述】:

给定一个数据框,其中的行对应于某些间隔的收益,我正在尝试获得每天的 n 分钟远期收益。

我已经尝试使用 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()

正如预期的那样,这将返回数据框中每一行的接下来 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

【问题讨论】:

标签: python pandas pandas-groupby rolling-computation


【解决方案1】:

我不知道您是否可以将其应用于 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]

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

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

似乎有人在这里使用 pandas 找到了解决方案:https://stackoverflow.com/a/56886389/5237560

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

【讨论】:

  • 感谢您的建议!我尝试使用转换来适应熊猫的解决方案,但似乎 groupby 日期和库存严重增加了时间。我现在正在做的(这似乎比我原来的解决方案更快)是向每个组转发一个计数器(窗口有限制),并通过按日期、库存和计数器分组并汇总回报来避免滚动
  • 非常感谢@alain-t 感谢您的帮助;这有效并节省了大量执行时间。我认为对于有很多组的情况,使用 cumsum() 绝对是最好的解决方案。
  • 不错的答案。就我而言,我必须这样做rollSum = np.roll(cumStocks[d:] - cumStocks[:-d], d)
猜你喜欢
  • 2019-11-15
  • 2019-09-16
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 2018-04-05
  • 1970-01-01
  • 2021-10-28
  • 1970-01-01
相关资源
最近更新 更多