Pandas 如何按条件筛选后每40场统计Team_1进球数并绘制年度变化图
实现按固定场次窗口求和的完整方案
原代码的核心问题定位
- 代码筛选出Team_1参与的有效比赛后,仅对前40行计算了一次固定总和,再把这个单值赋值给整列的
GoalSum,导致绘图时所有点的y值完全一致,最终呈现为水平直线 - 未按有效比赛的序列做独立切分,直接基于全量DataFrame的行索引做切片,会把无Team_1参与的无效比赛误计入计数序列
分步实现逻辑
- 过滤有效比赛数据:首先从原始DataFrame中筛出所有满足「主队/客队为Team_1、且
Team_1 Goals不为-1」的行,按比赛日期升序排序,确保比赛时序正确。非Team_1参与的无效比赛直接排除,不参与后续计数和求和。 - 按固定场次切分计算块:对排序后的有效比赛序列,每40场划分为一个独立计算单元——通过整数除法给每一场有效比赛分配组号,确保连续40场有效比赛归入同一组:
这个逻辑和你给出的3场为一个计算单元的示例完全匹配:valid_matches['group_id'] = np.arange(len(valid_matches)) // 40- 第0、1、2号有效比赛(对应原表索引0、1、2)会分到同一组,组内求和为
0+3+1=4,将这个值回填到组内最后一行(原表索引2)的GoalSum列 - 第3、4、5号有效比赛(对应原表索引3、4、5)会分到下一组,组内求和为
2+2+1=5,将这个值回填到组内最后一行(原表索引5)的GoalSum列
- 第0、1、2号有效比赛(对应原表索引0、1、2)会分到同一组,组内求和为
- 计算组内求和并回填:对每个
group_id分组计算Team_1 Goals的总和,把结果映射回原始DataFrame的对应位置,非计算块结尾的行GoalSum留空即可。 - 绘图实现:提取所有
GoalSum非空的行作为绘图点,x轴取对应行的Date年份,y轴取计算得到的GoalSum值,绘制的折线就会随每个计算块的进球总和波动,不会出现水平直线的问题。
可直接运行的示例代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 预处理原始数据 # 按需求过滤有效比赛 valid_mask = ((df["HomeTeam"] == "Team_1") | (df["OpponentTeam"] == "Team_1")) & (df["Team_1 Goals"] != -1) valid_matches = df[valid_mask].sort_values("Date").copy() # 按日期排序保证时序 # 初始化全量DataFrame的GoalSum列 df["GoalSum"] = np.nan # 每40场为一组计算求和 WINDOW_SIZE = 40 # 按需求调整窗口大小,如示例要3场就改成3 valid_matches["group_id"] = np.arange(len(valid_matches)) // WINDOW_SIZE # 计算每个组的进球总和 group_sum = valid_matches.groupby("group_id")["Team_1 Goals"].sum() # 把每个组的总和回填到对应组最后一行的原表位置 for gid, total_goal in group_sum.items(): current_group = valid_matches[valid_matches["group_id"] == gid] last_match_original_index = current_group.index[-1] df.loc[last_match_original_index, "GoalSum"] = total_goal # 绘制折线图 # 仅取有GoalSum值的行作为绘图点 plot_data = df.dropna(subset=["GoalSum"]).copy() plot_data["year"] = pd.to_datetime(plot_data["Date"]).dt.year plt.plot(plot_data["year"], plot_data["GoalSum"], marker='o') plt.xlabel("年份") plt.ylabel("每40场有效比赛进球总和") plt.show()
效果验证
用你给出的3场窗口的示例数据运行代码,把WINDOW_SIZE设为3,最终输出的GoalSum列会和预期结果完全一致:原表索引2的位置回填4,原表索引5的位置回填5,其余位置留空,绘图时只会提取这两个有值的点生成折线。结合你提到的「Team_1每年参赛超过40场」的前提,最终生成的折线会随每40场的进球数波动,不会出现水平直线的问题。
内容的提问来源于stack exchange,提问作者Mr. Engineer
相关产品推荐
相关产品推荐

