本文目录导读:

- 📑 目录导读
- 为什么用Python做赛季数据对比?
- 数据获取实战(爬虫 + API双方案)
- 数据清洗与结构标准化
- 累计数据对比算法(核心)
- 可视化呈现(动态对比图)
- 常见问题与避坑指南(FAQ)
- 延伸:如何扩展到多球队/多赛季
Python实战|赛季累计数据对比分析——从爬虫到可视化的全流程案例详解
📑 目录导读
- 为什么用Python做赛季数据对比?(场景与痛点)
- 数据获取实战(爬虫 + API双方案)
- 数据清洗与结构标准化(Pandas核心操作)
- 累计数据对比算法(滚动求和、分组对比、同比环比)
- 可视化呈现(Matplotlib/Plotly动态对比图)
- 常见问题与避坑指南(FAQ)
- 延伸:如何扩展到多球队/多赛季
为什么用Python做赛季数据对比?
在体育数据分析、游戏运营、电商年度大促等场景中,“赛季累计数据对比” 是最常见的需求——例如比较NBA本赛季与上赛季同期得分、游戏S1与S2赛季玩家活跃度、或电商双11第一周与第二周的累计GMV。
人工在Excel里做这种对比,一旦数据超过几千行,就会出现公式拖拽卡顿、维度切换麻烦、图表更新笨重等问题,而Python用Pandas处理数据 + 可视化库展示,能在10分钟内完成从清洗到出图的全流程,且可复用脚本处理每轮新数据。
数据获取实战(爬虫 + API双方案)
案例假设:我们需要分析“某篮球联赛2023赛季 vs 2024赛季前20轮每队的累计得分”。
方案A:Pandas读取本地CSV(最稳定)
import pandas as pd
df_2023 = pd.read_csv("season_2023_rounds.csv")
df_2024 = pd.read_csv("season_2024_rounds.csv")
方案B:Requests爬取公开数据(需遵守robots协议)
import requests
url = "https://api.sportradar.com/example/season/2024/round/20"
resp = requests.get(url, params={"api_key":"your_key"})
data = resp.json()
# 然后转入DataFrame
SEO提示:无论哪种方式,一定要保留“轮次”字段——它是计算累计值的关键维度。
数据清洗与结构标准化
原始数据常见问题:球队名称大小写不一致、轮次缺失、有重复行,我们写一个清洗函数:
def clean_season(df, season_label):
# 统一队名(首字母大写)
df["team"] = df["team"].str.title()
# 去除空白行
df = df.dropna(subset=["team", "round", "points"])
# 去重(一场比赛一行)
df = df.drop_duplicates(subset=["team", "round"])
# 添加赛季标签
df["season"] = season_label
return df
df_2023 = clean_season(df_2023, "2023")
df_2024 = clean_season(df_2024, "2024")
combined = pd.concat([df_2023, df_2024], ignore_index=True)
累计数据对比算法(核心)
1 单赛季内累计(滚动求和)
我们要计算每队“截至第N轮的总得分”:
combined["cum_points"] = combined.groupby(["season","team"])["points"].cumsum()
2 两个赛季的横向对比(按轮次对齐)
将2023和2024的累计值用pivot拉宽:
pivot_df = combined.pivot_table(
index=["team","round"],
columns="season",
values="cum_points"
).reset_index()
pivot_df.columns.name = None
pivot_df.rename(columns={"2023":"cum_2023", "2024":"cum_2024"}, inplace=True)
3 计算差值、同比或领先/落后轮次
pivot_df["diff"] = pivot_df["cum_2024"] - pivot_df["cum_2023"]
pivot_df["pct_change"] = (pivot_df["diff"] / pivot_df["cum_2023"]) * 100
# 找出2024首次反超2023的轮次
overtake = pivot_df[pivot_df["diff"] > 0].groupby("team")["round"].min()
可视化呈现(动态对比图)
静态折线图适合打印,动态交互图适合网页展示。
1 Matplotlib多子图(对比前5名球队)
import matplotlib.pyplot as plt
top_teams = pivot_df.groupby("team")["diff"].max().nlargest(5).index
fig, axes = plt.subplots(2, 3, figsize=(15, 8))
for i, team in enumerate(top_teams):
ax = axes[i//3][i%3]
sub = pivot_df[pivot_df["team"]==team]
ax.plot(sub["round"], sub["cum_2023"], label="2023")
ax.plot(sub["round"], sub["cum_2024"], label="2024")
ax.set_title(team)
ax.legend()
plt.tight_layout()
plt.savefig("season_compare.png", dpi=150)
2 Plotly动态交互(悬停查看每轮差值)
import plotly.express as px
fig = px.line(pivot_df, x="round", y=["cum_2023","cum_2024"],
color="team", facet_col="team", facet_col_wrap=2,
title="赛季累计得分对比")
fig.write_html("season_compare.html")
常见问题与避坑指南(FAQ)
Q1:两个赛季的比赛场次不一致怎么对齐?
解决方案:用
merge时指定on=["team","round"],赛季B缺失的轮次会变成NaN,用fillna(method="ffill")向前填充累计值。
Q2:累计值在赛季中后期波动大,如何突出变化趋势?
建议使用“7轮移动平均”或“每轮增量”而非纯累计,增量计算:
df.groupby("team")["points"].diff()。
Q3:数据量很大(百万行),groupby会不会卡死?
使用
dask.dataframe或polars替代Pandas,代码风格几乎不变,速度提升5-10倍。
Q4:如何处理球员交易导致球队得分权重变化?
引入“球员效率值”维度,在清洗阶段增加
player_id,累计计算时按球员分开后再合并。
Q5:图表中文显示方框?
加两行代码:
plt.rcParams['font.sans-serif']=['SimHei']和plt.rcParams['axes.unicode_minus']=False。
延伸:如何扩展到多球队/多赛季
如果你要做3个赛季以上的对比,建议把上面的pivot逻辑写成一个函数,循环处理每个赛季:
def build_season_cum(file_path, season_year):
df = pd.read_csv(file_path)
df = clean_season(df, season_year)
df["cum_points"] = df.groupby("team")["points"].cumsum()
return df
all_seasons = [build_season_cum(f"season_{y}_rounds.csv", y) for y in [2021,2022,2023,2024]]
full_df = pd.concat(all_seasons)
# 然后groupby("season","team","round")取最后一条即可
可以将对比结果导出为Excel(带条件格式高亮差值>0的单元格),或定时任务(cron / Airflow)自动跑脚本,生成每日更新报告。
用Python做赛季累计数据对比,核心就是 “分组-累计-对齐-差分-绘图” 五步,只要数据源稳定,整个脚本可复用且自动化,如果你现在面临类似“A/B赛季”或“今年 vs 去年”的数据分析需求,不妨按此流程跑一遍,你会发现对比结论和汇报图表在20分钟内就能完成,欢迎在评论区留下你的具体场景,我们一起讨论优化方案。