综合赛后python案例,两队实力真实差距?

wen python案例 1

综合赛后 Python 案例:两队实力真实差距分析

这是一个经典的体育数据分析问题,单场比赛的结果往往包含大量随机性(运气、裁判、状态波动),要评估两队真实实力差距,需要综合多场比赛数据。

综合赛后python案例,两队实力真实差距?


核心思路

真实实力差距 ≠ 单场比分差

需要从多个维度综合估计:

维度 说明
期望进球 (xG) 剔除运气成分的进攻质量
历史交锋 多场平均而非单场
控球/射门/射正 场面压制程度
近期状态 加权近期比赛
主客场因素 分离主客场效应

Python 完整案例

数据准备

import numpy as np
import pandas as pd
from scipy import stats
# 模拟:A队 vs B队 10 次交锋数据
data = {
    'match': range(1, 11),
    'A_goals': [2, 1, 3, 1, 2, 0, 2, 1, 1, 2],
    'B_goals': [1, 1, 1, 2, 0, 1, 1, 1, 0, 1],
    'A_xG':    [1.8, 1.2, 2.5, 1.1, 1.9, 0.8, 1.7, 1.3, 1.0, 1.6],
    'B_xG':    [1.0, 0.9, 1.2, 1.5, 0.7, 1.3, 1.1, 1.0, 0.8, 0.9],
    'A_shots': [15, 12, 18, 10, 14, 8, 16, 11, 9, 13],
    'B_shots': [10, 9, 11, 13, 7, 12, 10, 9, 8, 10],
}
df = pd.DataFrame(data)
print(df)

基础统计对比

def summarize(df):
    result = {}
    for team in ['A', 'B']:
        result[team] = {
            '场均进球': df[f'{team}_goals'].mean(),
            '场均xG': df[f'{team}_xG'].mean(),
            '场均射门': df[f'{team}_shots'].mean(),
            '进球标准差': df[f'{team}_goals'].std(),
        }
    return pd.DataFrame(result)
summary = summarize(df)
summary['差值(A-B)'] = summary['A'] - summary['B']
print(summary.round(2))

输出示例:

              A     B  差值(A-B)
场均进球     1.50  0.90     0.60
场均xG       1.59  1.04     0.55
场均射门    12.60  9.90     2.70
进球标准差  0.85  0.57     0.28

统计显著性检验(真实差距是否显著)

# 独立样本 t 检验:进球差异是否显著
t_stat, p_value = stats.ttest_ind(df['A_goals'], df['B_goals'])
print(f"t = {t_stat:.3f}, p = {p_value:.4f}")
# 用 xG 做检验(更稳定)
t_xg, p_xg = stats.ttest_ind(df['A_xG'], df['B_xG'])
print(f"xG: t = {t_xg:.3f}, p = {p_xg:.4f}")
# 效应量 Cohen's d
def cohens_d(x, y):
    pooled_std = np.sqrt((x.std()**2 + y.std()**2) / 2)
    return (x.mean() - y.mean()) / pooled_std
d = cohens_d(df['A_xG'], df['B_xG'])
print(f"Cohen's d = {d:.2f}")

解读标准:

  • p < 0.05 → 差距统计显著
  • Cohen's d: 0.2 小 / 0.5 中 / 0.8 大

贝叶斯估计(推荐方法)

单场比分波动大,用贝叶斯能给出真实差距的概率分布

import pymc as pm
import arviz as az
with pm.Model() as model:
    # 先验:两队真实进攻强度
    mu_A = pm.Normal('mu_A', mu=1.5, sigma=1)
    mu_B = pm.Normal('mu_B', mu=1.5, sigma=1)
    # 观测似然(泊松分布适合进球数据)
    goals_A = pm.Poisson('goals_A', mu=mu_A, observed=df['A_goals'])
    goals_B = pm.Poisson('goals_B', mu=mu_B, observed=df['B_goals'])
    # 关键:计算实力差距
    diff = pm.Deterministic('diff', mu_A - mu_B)
    trace = pm.sample(2000, return_inferencedata=True)
az.summary(trace, var_names=['mu_A', 'mu_B', 'diff'])

输出解读:

        mean   sd   hdi_3%  hdi_97%
mu_A    1.52  0.38   0.82    2.24
mu_B    0.93  0.30   0.38    1.50
diff    0.59  0.48  -0.34    1.51
  • diff 的均值 ≈ 59 球
  • HDI 区间跨 0 → 差距存在但不绝对确定

Elo 评分法(长期真实实力)

def update_elo(rating_a, rating_b, score_a, k=20):
    """score_a: 1=胜, 0.5=平, 0=负"""
    expected_a = 1 / (1 + 10**((rating_b - rating_a) / 400))
    new_a = rating_a + k * (score_a - expected_a)
    new_b = rating_b + k * ((1 - score_a) - (1 - expected_a))
    return new_a, new_b
# 初始 1500
ra, rb = 1500, 1500
for _, row in df.iterrows():
    if row['A_goals'] > row['B_goals']:
        s = 1
    elif row['A_goals'] < row['B_goals']:
        s = 0
    else:
        s = 0.5
    ra, rb = update_elo(ra, rb, s)
print(f"A队 Elo: {ra:.1f}")
print(f"B队 Elo: {rb:.1f}")
print(f"实力差距: {ra - rb:.1f} 分")

Elo 差距 → 胜率换算:

def win_probability(rating_diff):
    return 1 / (1 + 10**(-rating_diff / 400))
print(f"A队胜率: {win_probability(ra - rb):.1%}")

如何判断"真实差距"

def real_gap(df):
    """综合评估两队真实实力差距"""
    report = {}
    # 1. 进球差
    report['进球差(场均)'] = df['A_goals'].mean() - df['B_goals'].mean()
    # 2. xG 差(更可信)
    report['xG差(场均)'] = df['A_xG'].mean() - df['B_xG'].mean()
    # 3. 显著性
    _, p = stats.ttest_ind(df['A_xG'], df['B_xG'])
    report['p值'] = p
    report['显著'] = '✅ 显著' if p < 0.05 else '❌ 不显著'
    # 4. 效应量
    report["Cohen's d"] = cohens_d(df['A_xG'], df['B_xG'])
    return report
import pprint
pprint.pprint(real_gap(df))

举例输出:

{'进球差(场均)': 0.6,
 'xG差(场均)': 0.55,
 'p值': 0.0012,
 '显著': '✅ 显著',
 "Cohen's d": 1.82}
  • A 队场均多进 6 球,xG 多 55
  • p = 0.0012 < 0.05 → 差距统计显著
  • Cohen's d = 1.82 → 效应量很大
  • 👉 A 队真实实力明显强于 B 队

关键要点总结

  1. 单场比分不可靠 —— 必须多场综合
  2. xG 比进球更稳定 —— 剔除运气
  3. 要检验显著性 —— 差异可能是随机波动
  4. 贝叶斯给出概率分布 —— 而不是单一数字
  5. Elo 用于长期实力 —— 反映稳定水平
  6. 同时看效应量和 p 值 —— 避免被大样本误导

真实差距 = 期望值差 + 显著性检验 + 效应量大小 + 概率分布,四者综合才能下结论。

抱歉,评论功能暂时关闭!