优化Pandas groupby操作 高效计算多时间周期分组均值指标
解决方案
直接通过单轮分组+分组内时间筛选的方式完成所有周期的均值计算,全程无冗余数据生成,也无需循环创建/合并DataFrame:
实现代码
import pandas as pd import numpy as np # 原始数据生成逻辑 names = ['PersonA', 'PersonB', 'PersonC', 'PersonD','PersonE','PersonF'] team = ['Team1','Team2'] dates = pd.date_range(start = '2020-05-28', end = '2021-11-22') df = pd.DataFrame({'runtime': np.repeat(dates, len(names)*len(team))}) df['name'] = len(dates)*len(team)*names df['team'] = len(dates)*len(names)*team df['A'] = 40 + 20*np.random.random(len(df)) df['B'] = .1 * np.random.random(len(df)) df['C'] = 1 +.5 * np.random.random(len(df)) # 计算逻辑开始 # 1. 预处理:按分组+时间排序,保证时间顺序正确 df_sorted = df.sort_values(['name', 'team', 'runtime']).copy() # 2. 自定义周期和列后缀映射,后续加新周期直接修改这里即可 period_map = { '7D': 'w', # 最近7天(周) '30D': 'm', # 最近30天(月) '365D': 'y', # 最近365天(年) 'all': 'at' # 全时段 } # 要计算均值的字段 calc_cols = ['A', 'B', 'C'] # 3. 定义分组内计算函数 def calc_period_means(gdf): res = {} # 取当前分组的最大时间作为截止时间 max_dt = gdf['runtime'].max() for period, suffix in period_map.items(): # 筛选对应周期的数据 if period == 'all': period_df = gdf else: period_df = gdf[gdf['runtime'] >= max_dt - pd.Timedelta(period)] # 批量计算三个字段的均值 col_means = period_df[calc_cols].mean() for col in calc_cols: res[f'{col}_{suffix}'] = col_means[col] return pd.Series(res) # 4. 分组计算直接得到目标结构 result = df_sorted.groupby(['name', 'team'], as_index=False).apply(calc_period_means)
适配调整说明
- 如果需要使用自然月/自然年而非固定天数计算,把
pd.Timedelta(period)替换为pd.DateOffset(months=1)/pd.DateOffset(years=1)即可,自动适配闰月、闰年逻辑 - 新增计算周期仅需在
period_map中添加键值对,无需修改其他逻辑
方案优势
- 仅执行1次分组操作,无循环创建DataFrame、合并的额外开销
- 最终输出行数等于
人数*队伍数,也就是当前场景下的12行,完全没有冗余数据,无论时间跨度多大都不会出现数据膨胀 - 输出结构直接匹配需求,不需要额外做列删除、数据清洗操作
内容的提问来源于stack exchange,提问作者p3hndrx
相关产品推荐
相关产品推荐

