Pandas 0.22版本groupby+resample.first性能骤降原因及优化咨询
Pandas 0.22.0 分组后Resample性能下降的原因及优化方案
我之前升级Pandas版本时也碰到过一模一样的性能骤降问题,咱们来一步步拆解原因和解决办法:
为什么0.22.0版本变慢了?
Pandas 0.22.0对groupby后resample的底层逻辑做了架构重构:
- 旧版本(0.21.0及以前)针对分组后重采样的场景做了专门的向量优化,直接批量处理所有分组,完全避免了逐组循环的开销。
- 0.22.0为了支持更灵活的分组键(比如非哈希可迭代类型)和扩展resample的功能范围,改用了通用的逐组处理逻辑。这就导致当分组数量多、时间序列数据量大时,循环处理每个分组的额外开销被无限放大,最终出现速度降到原来1/20的极端情况。
如何在0.22.0中恢复同等性能?
这里有几个经过实际验证的优化方案,按推荐优先级排序:
1. 用多键GroupBy替代分组后Resample
既然你的需求是每个组内按天取第一个值,可以把时间索引转换为日期列,然后用「分组列+日期列」作为GroupBy的键直接取first。这个方法利用了Pandas多键GroupBy的向量优化特性,效率远高于逐组resample:
# 假设你的DataFrame是df,分组列为'group_id',时间索引是datetime类型 # 第一步:把时间索引转为日期列 df['date'] = df.index.date # 第二步:按分组列+日期列分组取first result = df.groupby(['group_id', 'date']).first() # 如果需要保持原有的层级索引结构,可以调整索引顺序 result = result.reorder_levels(['group_id', 'date'])
2. 优化分组列的数据类型
如果你的分组列是字符串或其他非分类类型,将其转为category类型可以大幅减少分组时的内存开销和计算时间:
df['group_id'] = df['group_id'].astype('category')
3. 手动批量处理(适合复杂业务场景)
如果业务逻辑必须使用resample(比如需要自动填充缺失日期),可以手动提取每个分组的时间序列,批量执行resample后再合并,避开Pandas内置分组resample的额外逻辑开销:
# 先获取所有分组的唯一标识 group_names = df['group_id'].unique() # 批量处理每个分组 resampled_dfs = [] for name in group_names: group_df = df[df['group_id'] == name] resampled = group_df.resample('1D').first() resampled['group_id'] = name resampled_dfs.append(resampled) # 合并所有分组的结果 result = pd.concat(resampled_dfs).set_index('group_id', append=True).reorder_levels(['group_id', 'datetime'])
性能验证
你可以用timeit模块快速对比不同方案的速度差异:
import timeit def original_method(): return df.groupby('group_id').resample('1D').first() def optimized_method(): temp_df = df.copy() temp_df['date'] = temp_df.index.date return temp_df.groupby(['group_id', 'date']).first() print("原方法耗时:", timeit.timeit(original_method, number=10)) print("优化方法耗时:", timeit.timeit(optimized_method, number=10))
内容的提问来源于stack exchange,提问作者Ferrard
相关产品推荐
相关产品推荐

