Pandas不使用iterrows按分组列最大值生成时序新行的方法
解决方案
实现思路
借助pandas分组聚合能力替代循环遍历,核心逻辑如下:
- 先按球员、赛季年龄排序,保证时序数据顺序正确
- 按球员维度分组,筛选出行数≥2的球员(不足2条历史数据无法计算两年平均值,不生成新行)
- 取每个球员的最后两行(对应最大的两个赛季年龄,也就是最大年龄往前推两年的数值)计算sa、ga的平均值
- 构造新行数据后和原表拼接即可
完整代码
import pandas as pd # 示例数据 data = [['Adam Wilcox', 8476330, 25, 14.0, 0.0], ['Adin Hill', 8478499, 21, 129.0, 14.0], ['Adin Hill', 8478499, 22, 322.0, 32.0], ['Adin Hill', 8478499, 23, 343.0, 28.0], ['Adin Hill', 8478499, 24, 530.0, 46.0], ['Adin Hill', 8478499, 25, 237.0, 26.0], ['Al Montoya', 8471219, 24, 120.0, 9.0], ['Al Montoya', 8471219, 26, 585.0, 46.0], ['Al Montoya', 8471219, 27, 832.0, 89.0], ['Al Montoya', 8471219, 28, 168.0, 17.0]] model_df = pd.DataFrame(data, columns=['player', 'player_id', 'season_age', 'sa', 'ga']) # 按球员和赛季年龄排序,保证时序正确 model_df = model_df.sort_values(['player', 'player_id', 'season_age']).reset_index(drop=True) def gen_new_row(group): # 不足2条历史数据不生成新行 if len(group) < 2: return pd.Series(dtype='float64') # 取最后两年的平均值,转为整数和示例格式对齐 avg_sa = group['sa'].tail(2).mean().astype(int) avg_ga = group['ga'].tail(2).mean().astype(int) return pd.Series({ 'player': group['player'].iloc[0], 'player_id': group['player_id'].iloc[0], 'season_age': group['season_age'].max() + 1, 'sa': avg_sa, 'ga': avg_ga }) # 生成新行数据,过滤空行 new_rows = model_df.groupby(['player', 'player_id'], as_index=False).apply(gen_new_row).dropna() # 拼接原数据和新行 model_df = pd.concat([model_df, new_rows], ignore_index=True) print(model_df.values.tolist())
代码优势
- 无需循环遍历,数据量大时性能远高于iterrows实现
- 自动处理时序排序,避免原表年龄顺序混乱导致的取值错误
- 自动过滤不足两年数据的球员,鲁棒性更强
- 代码简洁易维护,符合pandas最佳实践
内容的提问来源于stack exchange,提问作者Matthew Barlowe
相关产品推荐
相关产品推荐

