本文介绍一种比 `groupby().apply(rolling())` 快约 15 倍的替代方案:利用 `set_index + groupby().rolling()` 链式操作后合并回原表,大幅提升大规模时序分组滚动计算性能。
在处理高频、多维度的时序数据(如*历史战绩)时,常需对“ horse–trainer 组合”等复合键,在时间窗口(如过去 180 天)内计算滚动统计量(如平均得分)。原始写法虽语义清晰,但性能瓶颈明显:
# ❌ 原始低效写法(约 18.5 秒 / 10 万行)
df['HorseRaceCount90d'] = (
df.groupby(['Horse', 'Trainer'], group_keys=False)
.apply(lambda x: x.rolling(window='180D', on='RaceDate', min_periods=1)['Points'].mean())
)该方式对每个分组单独执行 rolling(..., on='RaceDate'),触发大量重复索引对齐与时间窗口判定,且 apply 无法被 Pandas 内部优化器有效向量化。
✅ 更优解:先设时间列为索引,再分组滚动,最后精准回填
# ✅ 优化写法(约 1.18 秒 / 10 万行,提速 15×)
rolling_result = (
df.set_index('RaceDate')
.groupby(['Horse', 'Trainer'])['Points']
.rolling('180D', min_periods=1)
.mean()
.rename('HorseRaceCount90d')
)
df = df.merge(
rolling_result,
left_on=['Horse', 'Trainer', 'RaceDate'],
right_index=True,
how='left'
)关键优化原理:
注意事项:

总结:
避免在 groupby().apply() 中嵌套 rolling(..., on=...) —— 改用“索引化→分组滚动→合并回表”三步范式,是提升 Pandas 时间窗口分组计算速度最简单、最有效的方式之一。实测性能提升达 15 倍以上,且代码更简洁、可维护性更强。