python案例如何预测杯赛决赛的紧张程度?

wen python案例 4

预测杯赛决赛紧张程度的Python案例

这是一个有趣的机器学习/数据分析问题,下面给出一个完整的实战案例,用特征工程 + 机器学习来预测决赛的"紧张程度"。

python案例如何预测杯赛决赛的紧张程度?

问题定义

"紧张程度"量化指标(可组合成综合分数 tension_score,0-100):

  • 比分差距(越小越紧张)
  • 加时/点球(有则大幅加分)
  • 红黄牌数量
  • 犯规次数
  • 射门/射正差距
  • 历史交手平局率
  • 两队实力差距(FIFA排名/ELO差值)

完整代码实现

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error, r2_score
import matplotlib.pyplot as plt
# ============ 1. 构造/加载数据 ============
# 真实项目可从 FIFA API、Kaggle 世界杯数据集加载
# 这里构造示例数据(每行是一场决赛)
np.random.seed(42)
n = 200
data = pd.DataFrame({
    # 赛前特征
    'elo_diff':          np.random.randint(0, 400, n),        # 两队ELO差
    'h2h_draw_rate':     np.random.rand(n),                    # 历史平局率
    'h2h_avg_goals':     np.random.uniform(1.5, 4.0, n),       # 历史场均进球
    'rest_days_diff':    np.random.randint(-3, 4, n),          # 休息天数差
    'is_host_playing':   np.random.randint(0, 2, n),           # 东道主是否参赛
    'final_experience':  np.random.randint(0, 5, n),           # 大赛决赛经验差
    # 赛后特征(用于训练,也可用赛中实时数据)
    'goal_diff':         np.random.choice([0,0,0,1,1,2,3], n),
    'went_to_extra':     np.random.choice([0,1], n, p=[0.7,0.3]),
    'went_to_penalty':   np.random.choice([0,1], n, p=[0.9,0.1]),
    'yellow_cards':      np.random.randint(0, 8, n),
    'red_cards':         np.random.randint(0, 3, n),
    'total_fouls':       np.random.randint(15, 40, n),
    'shot_diff':         np.random.randint(0, 10, n),
})
# ============ 2. 构造目标:紧张程度分数 ============
def calc_tension(row):
    score = 0
    score += max(0, 40 - row['goal_diff'] * 15)          # 比分接近
    score += row['went_to_extra'] * 15                    # 加时
    score += row['went_to_penalty'] * 20                  # 点球
    score += min(row['yellow_cards'] * 2, 10)             # 黄牌
    score += row['red_cards'] * 5                         # 红牌
    score += max(0, 10 - row['shot_diff'])                # 射门接近
    score += (400 - row['elo_diff']) / 10                 # 实力接近 → 更紧张
    score += row['h2h_draw_rate'] * 10
    return max(0, min(100, score))
data['tension_score'] = data.apply(calc_tension, axis=1)
# ============ 3. 建模 ============
# 假设赛前只能拿到"赛前特征"来做预测(避免数据泄漏)
pre_match_features = [
    'elo_diff', 'h2h_draw_rate', 'h2h_avg_goals',
    'rest_days_diff', 'is_host_playing', 'final_experience'
]
X = data[pre_match_features]
y = data['tension_score']
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s  = scaler.transform(X_test)
models = {
    'RandomForest': RandomForestRegressor(n_estimators=300, random_state=42),
    'GradientBoosting': GradientBoostingRegressor(n_estimators=300, learning_rate=0.05,
                                                  max_depth=3, random_state=42)
}
for name, model in models.items():
    model.fit(X_train_s, y_train)
    pred = model.predict(X_test_s)
    print(f"{name}: MAE={mean_absolute_error(y_test, pred):.2f}, "
          f"R²={r2_score(y_test, pred):.3f}")
# ============ 4. 特征重要性 ============
best = models['GradientBoosting']
imp = pd.Series(best.feature_importances_, index=pre_match_features).sort_values()
plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文显示
plt.rcParams['axes.unicode_minus'] = False
imp.plot(kind='barh', figsize=(8, 4), title='赛前特征对紧张程度的影响')
plt.tight_layout(); plt.show()
# ============ 5. 预测一场新决赛 ============
new_final = pd.DataFrame([{
    'elo_diff': 50,              # 两队实力非常接近
    'h2h_draw_rate': 0.4,        # 历史交手平局率高
    'h2h_avg_goals': 2.1,        # 场均进球偏低
    'rest_days_diff': 0,
    'is_host_playing': 1,
    'final_experience': 1
}])
score = best.predict(scaler.transform(new_final))[0]
print(f"\n预测紧张程度分数:{score:.1f} / 100")

关键设计要点

特征设计分两阶段

阶段 特征 用途
赛前 ELO差、历史平局率、休息天数、决赛经验 赛前预测
赛中实时 当前比分差、红黄牌、加时标志 实时紧张度预测

目标标签的三种构造方式

  • 规则打分(如上):简单可控,但主观
  • 专家标注:真实比赛人工打分 0-10
  • 信号替代:用"最后10分钟观众心率/社交媒体峰值"作代理目标

避免数据泄漏

预测"赛前紧张程度"时,绝不能使用赛后特征(goal_diff、went_to_penalty),上面的示例把它们放在数据表里,但建模时只用了 pre_match_features。

进阶方向

  1. 实时紧张度曲线:用逐分钟事件流(进球、红牌、射门、控球率),LSTM/Transformer 预测每时刻紧张度。
  2. 概率化输出:用 QuantileRegressor 输出紧张度的 25%/75% 分位,给"最可能范围"。
  3. 多模态:结合社交媒体情绪(NLP)、赔率变化(博彩数据)提升准确率。
  4. 可解释性:用 SHAP 解释每场决赛为何被判为"特别紧张"。
# SHAP 示例
import shap
explainer = shap.TreeExplainer(best)
shap_values = explainer.shap_values(X_test_s)
shap.summary_plot(shap_values, X_test, feature_names=pre_match_features)

现实案例参考

  • 2022世界杯决赛(阿根廷vs法国):ELO接近、历史平局多、进攻火力相当 → 模型会给出极高紧张度(实际3-3后点球)。
  • 2018世界杯决赛(法国vs克罗地亚):ELO差较大 → 赛前预测紧张度偏低(实际4-2较开放)。

如果你有真实数据集(如 Kaggle "FIFA World Cup" 或 football-data.org API),我可以帮你改写上面的代码接入真实数据,或者进一步做逐分钟实时紧张度预测模型,你更倾向哪个方向?

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

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝