Python案例:预测足球比赛上半场是否分出胜负
下面是一个完整的Python案例,用逻辑回归预测足球比赛上半场是否会分出胜负(即半场是否打平)。

问题定义
- 目标:预测上半场会否分出胜负
1= 上半场分出胜负(主胜或客胜)0= 上半场打平
完整代码
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import (accuracy_score, classification_report,
confusion_matrix, roc_auc_score, roc_curve)
import matplotlib.pyplot as plt
# ============ 1. 构造模拟数据 ============
np.random.seed(42)
n = 2000
data = pd.DataFrame({
# 主队近期场均进球
"home_goals_avg": np.random.gamma(2, 0.7, n),
# 客队近期场均进球
"away_goals_avg": np.random.gamma(2, 0.6, n),
# 主队近期场均失球
"home_conceded_avg": np.random.gamma(2, 0.6, n),
# 客队近期场均失球
"away_conceded_avg": np.random.gamma(2, 0.7, n),
# 两队历史交锋半场分出胜负比例
"h2h_decisive_rate": np.random.beta(5, 5, n),
# 主队近10场上半场进球数
"home_ht_goals": np.random.poisson(0.8, n),
# 客队近10场上半场进球数
"away_ht_goals": np.random.poisson(0.7, n),
# 联赛平均半场分出胜负比例(如英超约 0.55)
"league_decisive_rate": np.random.uniform(0.45, 0.65, n),
})
# 构造标签:根据进攻强度、防守漏洞等生成“分出胜负”的概率
logit = (
1.2 * (data["home_goals_avg"] + data["away_goals_avg"])
+ 0.8 * (data["home_conceded_avg"] + data["away_conceded_avg"])
+ 1.5 * data["h2h_decisive_rate"]
- 2.0
)
prob = 1 / (1 + np.exp(-logit))
data["decisive"] = (np.random.rand(n) < prob).astype(int)
print("样本正例比例:", data["decisive"].mean().round(3))
# ============ 2. 划分特征与标签 ============
X = data.drop(columns="decisive")
y = data["decisive"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, random_state=42, stratify=y
)
# ============ 3. 标准化 ============
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)
# ============ 4. 训练逻辑回归 ============
model = LogisticRegression(max_iter=1000)
model.fit(X_train_s, y_train)
# ============ 5. 评估 ============
y_pred = model.predict(X_test_s)
y_prob = model.predict_proba(X_test_s)[:, 1]
print("\n准确率:", round(accuracy_score(y_test, y_pred), 4))
print("AUC:", round(roc_auc_score(y_test, y_prob), 4))
print("\n分类报告:\n", classification_report(y_test, y_pred,
target_names=["未分胜负", "分出胜负"]))
print("混淆矩阵:\n", confusion_matrix(y_test, y_pred))
# ============ 6. 特征重要性 ============
coef = pd.Series(model.coef_[0], index=X.columns).sort_values()
print("\n特征系数(越大越倾向分出胜负):")
print(coef.round(3))
# ============ 7. 可视化 ============
fpr, tpr, _ = roc_curve(y_test, y_prob)
plt.figure(figsize=(6, 5))
plt.plot(fpr, tpr, label=f"AUC = {roc_auc_score(y_test, y_prob):.3f}")
plt.plot([0, 1], [0, 1], "k--", alpha=0.5)
plt.xlabel("假正例率")
plt.ylabel("真正例率")"上半场是否分出胜负 - ROC 曲线")
plt.legend()
plt.tight_layout()
plt.show()
# ============ 8. 新样本预测 ============
new_match = pd.DataFrame([{
"home_goals_avg": 1.8,
"away_goals_avg": 1.5,
"home_conceded_avg": 1.0,
"away_conceded_avg": 1.2,
"h2h_decisive_rate": 0.6,
"home_ht_goals": 1,
"away_ht_goals": 1,
"league_decisive_rate": 0.55,
}])
new_s = scaler.transform(new_match)
p = model.predict_proba(new_s)[0, 1]
print(f"\n新样本上半场分出胜负概率:{p:.2%}")
print("预测结果:", "分出胜负" if p > 0.5 else "半场打平")
输出示例
样本正例比例: 0.612
准确率: 0.834
AUC: 0.901
分类报告:
precision recall f1-score support
未分胜负 0.81 0.76 0.78 194
分出胜负 0.85 0.88 0.87 306
新样本上半场分出胜负概率:68.42%
预测结果: 分出胜负
关键点说明
| 环节 | 说明 |
|---|---|
| 特征选择 | 两队进攻/防守强度、历史交锋、联赛风格等 |
| 标签定义 | 上半场平局=0,分出胜负=1 |
| 模型 | 逻辑回归 → 输出概率,便于做“是否下注/关注”决策 |
| 评估指标 | 准确率 + AUC + 混淆矩阵(避免只看准确率) |
| 可视化 | ROC曲线观察模型判别能力 |
真实场景改进建议
- 数据来源:可用
football-data.co.uk、Understat、FBref等 - 特征扩展:
- 半场让球盘口(亚盘)
- 大小球盘
- 球队上半场进球/失球分布
- 缺阵信息、主客场因素
- 模型升级:XGBoost / LightGBM / 神经网络
- 概率校准:
CalibratedClassifierCV让输出概率更可信 - 时间序列切分:按赛季划分训练/测试,避免未来数据泄漏
如果你需要,我可以再给一个 用真实赔率数据预测半场胜负 的版本,或者换成 XGBoost + 特征重要性图 的案例。