Pandas如何通过groupby实现按日期递增的滚动数据切片聚合
基于pandas原生方法的滚动累计聚合实现
问题说明
现有跑步群体运动数据集,单条记录包含跑者姓名、跑步日期、跑步里程三个字段,需要生成随日期推进、统计范围持续扩大的累计数据切片,按跑者聚合得到截至每个日期节点的累计运动数据。原有逐日期循环筛选的实现方式在大数据量下性能较差,可通过pandas原生分组、重索引、累计计算逻辑替代,性能提升显著。
示例数据集构造代码:
import pandas as pd df=pd.DataFrame({'name': 'Jack Jill Bob Bella Norm Nella Jack Jill Bob Bella Norm Nella Jack Jill Bob Bella Norm Nella'.split(), 'date': '05-04-2021 05-04-2021 05-04-2021 06-04-2021 05-04-2021 06-04-2021 06-04-2021 08-04-2021 11-04-2021 08-04-2021 11-04-2021 08-04-2021 11-04-2021 11-04-2021 15-04-2022 15-04-2022 18-04-2022 19-04-2022'.split(), 'km': [5.85, 5.18, 13.58, 14.45, 14.58, 11.14, 8.85, 10.77, 12.54, 7.09, 7.69, 11.64, 9.82, 11.20, 10.33, 11.31, 14.66, 12.56]}) df['date']=pd.to_datetime(df['date'], infer_datetime_format=True)
原有循环实现参考:
for d in df.date.unique(): rolling=df[df.date <= d].groupby('name').sum() rolling['date']=d
高性能原生实现代码
核心逻辑为先补全所有日期-跑者的完整组合,再按跑者分组做累计计算,全程仅需两次分组操作,无需逐日期遍历全表:
# 1. 先聚合得到每个日期下单个跑者的当日运动总里程 daily_agg = df.groupby(['date', 'name'], as_index=False)['km'].sum() # 2. 生成所有唯一日期、所有跑者的完全交叉索引,避免漏算无跑步记录的跑者 full_cross_index = pd.MultiIndex.from_product( [df['date'].sort_values().unique(), df['name'].unique()], names=['date', 'name'] ) # 3. 重索引补全缺失记录,当日无跑步记录的里程填0 daily_full = daily_agg.set_index(['date', 'name']).reindex(full_cross_index, fill_value=0).reset_index() # 4. 按跑者分组做累计求和,得到截至每个日期的累计里程 daily_full['total_km'] = daily_full.sort_values('date').groupby('name')['km'].cumsum()
最终输出的daily_full表中,每一行对应某一日期节点下单个跑者的累计跑步里程,和原有循环逻辑输出结果完全一致。
复杂聚合逻辑扩展
如果需要实现除求和外的更复杂聚合(比如累计跑步次数、单次最高里程、累计平均里程等),可以用分组后的expanding()扩展窗口实现,支持自定义聚合函数:
# 按跑者分组,对历史全量数据做多维度聚合 complex_agg = daily_full.sort_values(['name', 'date']).groupby('name')['km'].expanding().agg( total_km = 'sum', run_count = lambda x: (x > 0).sum(), max_single_km = 'max', avg_km = 'mean' ).reset_index(drop=True) # 拼接日期、姓名字段得到最终结果 result = pd.concat( [daily_full[['date', 'name']].sort_values(['name', 'date']).reset_index(drop=True), complex_agg], axis=1 )
性能说明
- 原有循环方案时间复杂度为O(nd)*,n为总记录数,d为唯一日期数,每遍历一个日期就要全表扫描做一次筛选和分组,十万级以上数据性能衰减明显。
- 原生实现方案时间复杂度接近O(n),仅需固定次数的全表操作,百万级数据可在秒级完成计算。
内容的提问来源于stack exchange,提问作者Dave-C
相关产品推荐
相关产品推荐

