本文目录导读:

量化主队球迷人数对比赛的影响,是体育数据分析中一个经典且有趣的课题,要科学地做到这一点,需要从数据获取、变量控制、模型构建三个层面来设计脚本和分析框架。
下面是一个完整的实操思路:
核心逻辑
主队球迷人数影响比赛的方式通常有:
- 裁判偏向(主场哨)
- 球员心理/士气提升
- 客队沟通受阻(噪音)
- 生理因素(客队旅途+环境陌生)
量化目标:隔离出球迷人数这一变量对比赛结果的边际贡献。
数据获取脚本
需要的数据字段
| 类别 | 字段 |
|---|---|
| 比赛结果 | 主队进球、客队进球、胜负、净胜球 |
| 球迷数据 | 官方上座人数、球场容量、上座率 |
| 控制变量 | 两队Elo/FIFA排名、近期状态、伤停、休息天数 |
| 环境 | 天气、比赛时间、赛事类型 |
| 特殊时期 | 疫情空场(天然实验) |
数据源示例
import pandas as pd
import numpy as np
import statsmodels.api as sm
# 示例:读取比赛数据
df = pd.read_csv("matches.csv")
# 字段: home_goals, away_goals, attendance, capacity,
# home_elo, away_elo, rest_days_diff, is_covid, ...
df["attendance_rate"] = df["attendance"] / df["capacity"]
df["elo_diff"] = df["home_elo"] - df["away_elo"]
df["goal_diff"] = df["home_goals"] - df["away_goals"]
量化方法(由浅入深)
方法1:相关性分析(快速探索)
corr = df[["attendance", "goal_diff", "home_win"]].corr() print(corr)
⚠️ 问题:相关性 ≠ 因果,强队球迷多,赢球也多,存在内生性。
方法2:多元回归(控制混杂变量)
X = df[["attendance_rate", "elo_diff", "rest_days_diff"]] X = sm.add_constant(X) y = df["goal_diff"] model = sm.OLS(y, X).fit() print(model.summary())
解读系数:在控制实力差距后,上座率每提升10%,主队净胜球平均增加多少。
但仍有问题:球迷人数可能被比赛重要性影响(重要比赛人多+强队)。
方法3:新冠疫情空场——天然实验
这是目前学术界最常用的准自然实验方法:
# 对比:有观众 vs 空场
covid = df[df["is_covid"] == 1]
normal = df[df["is_covid"] == 0]
# 主队胜率对比
print("空场主胜率:", (covid["home_goals"] > covid["away_goals"]).mean())
print("正常主胜率:", (normal["home_goals"] > normal["away_goals"]).mean())
# 更严谨:双重差分 (DID)
# 处理组:疫情期;对照组:疫情前同期
经典结论(Bryson et al., 2021;Fischer & Haucap, 2021):
- 空场使主队优势下降约 50%
- 主要影响的是裁判判罚(主场哨减少),而非球员表现
方法4:断点回归(容量阈值)
利用球场容量作为外生阈值:
# 当上座接近容量上限时,球迷影响可能非线性 df["near_capacity"] = (df["attendance_rate"] > 0.95).astype(int)
对比接近满座 vs 未满座的比赛,控制其他变量。
方法5:面板数据固定效应
控制球队、赛季的固定特征:
# 使用 linearmodels
from linearmodels.panel import PanelOLS
df = df.set_index(["team_id", "season"])
mod = PanelOLS(df["goal_diff"],
sm.add_constant(df[["attendance_rate", "elo_diff"]]),
entity_effects=True, time_effects=True)
print(mod.fit())
这样能剔除“球队本身强弱”和“赛季整体趋势”的干扰。
进阶:区分影响渠道
想更精细,可以分别建模:
| 因变量 | 反映的渠道 |
|---|---|
| 主队进球数 | 进攻端激励 |
| 客队进球数 | 客队受干扰 |
| 主队黄牌数 / 客队黄牌数 | 裁判偏向 |
| 主队犯规数 | 裁判尺度 |
| 控球率、射门数 | 球员表现 |
for target in ["home_goals", "away_goals", "home_yellow", "away_yellow"]:
m = sm.OLS(df[target], X).fit()
print(target, "coef:", m.params["attendance_rate"], "p:", m.pvalues["attendance_rate"])
常见陷阱
- 内生性:球迷多 ← 球队强 ← 赢球多,必须控制实力。
- 反向因果:成绩好 → 球迷多。
- 样本选择:只分析有观众的比赛会偏。
- 非线性:球迷影响可能边际递减(5万人 vs 8万人差别不大)。
- 疫情混淆:空场期同时有赛程密集、训练中断等因素,需用DID剔除。
一个可复用的完整脚本骨架
import pandas as pd, numpy as np, statsmodels.api as sm
def quantify_home_crowd_effect(df):
df = df.copy()
df["attendance_rate"] = df["attendance"] / df["capacity"]
df["elo_diff"] = df["home_elo"] - df["away_elo"]
df["goal_diff"] = df["home_goals"] - df["away_goals"]
df["home_win"] = (df["goal_diff"] > 0).astype(int)
# 主模型
X = sm.add_constant(df[["attendance_rate", "elo_diff", "rest_days_diff"]])
ols = sm.OLS(df["goal_diff"], X).fit()
# 空场对比
covid_gap = df[df.is_covid==1]["home_win"].mean() - df[df.is_covid==0]["home_win"].mean()
return {
"attendance_coef": ols.params["attendance_rate"],
"p_value": ols.pvalues["attendance_rate"],
"covid_home_win_gap": covid_gap,
"summary": ols.summary()
}
result = quantify_home_crowd_effect(df)
print(result["attendance_coef"], result["p_value"])
结论参考(文献共识)
- 每增加 10,000 名球迷,主队净胜球约增加 1–0.2
- 空场使主队胜率下降 10–15 个百分点
- 影响主要通过裁判判罚而非球员技术表现
- 效果在强弱对话中更明显(弱主队靠球迷“爆冷”)
如果你告诉我具体场景(足球/篮球、数据来源、是否有疫情空场数据),我可以帮你写出针对性的脚本和模型选择建议。