足球比赛上半场胜负预测案例
这是一个典型的二分类预测问题,我用 Python 构建一个完整案例,演示如何预测上半场是否分出胜负(即上半场是否有进球导致比分不同)。

完整代码案例
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, confusion_matrix, roc_auc_score
from sklearn.preprocessing import StandardScaler
# ========== 1. 构造模拟数据 ==========
np.random.seed(42)
n = 2000
data = pd.DataFrame({
# 主队上半场平均进球能力
'home_goals_1h_avg': np.random.poisson(0.7, n),
# 客队上半场平均进球能力
'away_goals_1h_avg': np.random.poisson(0.5, n),
# 主队近期上半场进球率
'home_1h_scoring_rate': np.random.uniform(0, 1, n),
# 客队近期上半场进球率
'away_1h_scoring_rate': np.random.uniform(0, 1, n),
# 两队上半场失球率
'home_1h_concede_rate': np.random.uniform(0, 1, n),
'away_1h_concede_rate': np.random.uniform(0, 1, n),
# 主队上半场控球率
'home_possession': np.random.uniform(0.35, 0.65, n),
# 历史交锋上半场分出胜负比例
'h2h_1h_decided_rate': np.random.uniform(0.2, 0.8, n),
# 联赛平均上半场进球数
'league_1h_goals': np.random.uniform(0.8, 1.5, n),
})
# 生成标签(模拟真实规律):上半场是否分出胜负
# 逻辑:进球能力越强、交锋历史越容易分出胜负,概率越高
logit = (
1.5 * data['home_goals_1h_avg']
+ 1.2 * data['away_goals_1h_avg']
+ 1.0 * data['h2h_1h_decided_rate']
+ 0.8 * (data['home_1h_scoring_rate'] + data['away_1h_scoring_rate'])
+ 0.5 * data['league_1h_goals']
- 4.5
)
prob = 1 / (1 + np.exp(-logit))
data['y'] = (np.random.rand(n) < prob).astype(int) # 1=分出胜负, 0=平局
print("标签分布:")
print(data['y'].value_counts(normalize=True))
# ========== 2. 划分数据 ==========
X = data.drop('y', axis=1)
y = data['y']
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)
lr = LogisticRegression(max_iter=1000)
lr.fit(X_train_s, y_train)
y_pred_lr = lr.predict(X_test_s)
y_prob_lr = lr.predict_proba(X_test_s)[:, 1]
print("\n===== 逻辑回归 =====")
print(classification_report(y_test, y_pred_lr))
print("AUC:", round(roc_auc_score(y_test, y_prob_lr), 4))
# ========== 4. 随机森林模型 ==========
rf = RandomForestClassifier(n_estimators=300, max_depth=8, random_state=42)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)
y_prob_rf = rf.predict_proba(X_test)[:, 1]
print("\n===== 随机森林 =====")
print(classification_report(y_test, y_pred_rf))
print("AUC:", round(roc_auc_score(y_test, y_prob_rf), 4))
# ========== 5. 特征重要性 ==========
imp = pd.Series(rf.feature_importances_, index=X.columns).sort_values(ascending=False)
print("\n特征重要性:")
print(imp)
# ========== 6. 混淆矩阵 ==========
print("\n混淆矩阵 (0=平局, 1=分出胜负):")
print(confusion_matrix(y_test, y_pred_rf))
关键设计思路
问题定义
- 正类 (1):上半场分出胜负(包括主队领先或客队领先)
- 负类 (0):上半场平局(0:0 或 1:1 等)
核心特征
| 类别 | 特征示例 |
|---|---|
| 球队进攻 | 上半场平均进球、近期半场进球率 |
| 球队防守 | 半场失球率、被进球概率 |
| 对阵特征 | 历史交锋半场分出胜负比例 |
| 联赛特征 | 联赛平均半场进球数 |
| 战术 | 控球率、射门转化率 |
模型选择
- 逻辑回归:可解释性强,能输出概率
- 随机森林 / XGBoost:处理非线性关系更好
- AUC 指标比准确率更适合评估
实战注意事项
- 数据获取:可用
requests爬取或调用 Football-Data.org、SportsMonk 等 API - 类别不平衡:实际比赛中上半场平局占比约 40-50%,需用
class_weight='balanced' - 时间序列切分:不能用随机划分,应按时