利用友谊赛数据做预测的Python案例
友谊赛数据预测是一个典型的机器学习问题,常见于足球、篮球等体育赛事预测,下面我给出一个完整的Python案例框架。

数据理解
友谊赛数据的特点:
- 优点:提供额外的样本,尤其是国家队/球队间交手数据
- 缺点:球队可能不全力出战、阵容轮换、动机不足,噪音大
- 用途:作为常规赛事的补充特征,或用于冷启动(新球队/新赛季)
完整案例(足球比分预测)
数据准备
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score, classification_report
import matplotlib.pyplot as plt
# 假设数据格式:date, home_team, away_team, home_goals, away_goals, match_type
df = pd.read_csv('matches.csv', parse_dates=['date'])
df = df.sort_values('date').reset_index(drop=True)
print(df.head())
特征工程(核心)
友谊赛数据的关键是提取球队近期状态,但要用时间窗口避免数据泄漏。
def compute_team_form(df, team, current_date, window=10, match_types=None):
"""计算某球队在 current_date 之前的近 window 场表现"""
mask = (
((df['home_team'] == team) | (df['away_team'] == team)) &
(df['date'] < current_date)
)
if match_types:
mask &= df['match_type'].isin(match_types)
recent = df[mask].tail(window)
if len(recent) == 0:
return {'goals_for': 0, 'goals_against': 0, 'win_rate': 0, 'n': 0}
gf, ga, wins = [], [], 0
for _, row in recent.iterrows():
if row['home_team'] == team:
gf.append(row['home_goals']); ga.append(row['away_goals'])
if row['home_goals'] > row['away_goals']: wins += 1
else:
gf.append(row['away_goals']); ga.append(row['home_goals'])
if row['away_goals'] > row['home_goals']: wins += 1
return {
'goals_for': np.mean(gf),
'goals_against': np.mean(ga),
'win_rate': wins / len(recent),
'n': len(recent)
}
def build_features(df, friendly_weight=0.5):
"""构建特征:区分正式赛与友谊赛,友谊赛按权重衰减"""
features = []
for idx, row in df.iterrows():
# 分别统计正式赛、友谊赛表现
home_official = compute_team_form(df, row['home_team'], row['date'],
window=10, match_types=['official'])
away_official = compute_team_form(df, row['away_team'], row['date'],
window=10, match_types=['official'])
home_friendly = compute_team_form(df, row['home_team'], row['date'],
window=10, match_types=['friendly'])
away_friendly = compute_team_form(df, row['away_team'], row['date'],
window=10, match_types=['friendly'])
features.append({
'home_gf_off': home_official['goals_for'],
'home_ga_off': home_official['goals_against'],
'home_wr_off': home_official['win_rate'],
'away_gf_off': away_official['goals_for'],
'away_ga_off': away_official['goals_against'],
'away_wr_off': away_official['win_rate'],
# 友谊赛数据加权(体现其参考价值较低)
'home_gf_fr': home_friendly['goals_for'] * friendly_weight,
'away_gf_fr': away_friendly['goals_for'] * friendly_weight,
'is_friendly': 1 if row['match_type'] == 'friendly' else 0,
# 关键特征:实力差
'attack_diff': home_official['goals_for'] - away_official['goals_against'],
'defense_diff': home_official['goals_against'] - away_official['goals_for'],
'form_diff': home_official['win_rate'] - away_official['win_rate'],
})
return pd.DataFrame(features)
# 标签:主胜/平/客胜
df['result'] = np.where(df['home_goals'] > df['away_goals'], 2,
np.where(df['home_goals'] == df['away_goals'], 1, 0))
X = build_features(df)
y = df['result']
模型训练(时间序列切分,避免未来数据泄漏)
# 按时间切分,前80%训练,后20%测试
split = int(len(df) * 0.8)
X_train, X_test = X.iloc[:split], X.iloc[split:]
y_train, y_test = y.iloc[:split], y.iloc[split:]
model = GradientBoostingClassifier(n_estimators=200, max_depth=4,
learning_rate=0.05, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print("准确率:", accuracy_score(y_test, y_pred))
print(classification_report(y_test, y_pred,
target_names=['客胜', '平局', '主胜']))
# 特征重要性
imp = pd.Series(model.feature_importances_, index=X.columns).sort_values()
imp.plot(kind='barh', figsize=(8, 6))'特征重要性')
plt.tight_layout()
plt.show()
概率预测(可用于赔率对比)
proba = model.predict_proba(X_test)
# 输出每场比赛三个结果的概率
for i, p in enumerate(proba[:5]):
print(f"比赛{i}: 客胜={p[0]:.2%}, 平={p[1]:.2%}, 主胜={p[2]:.2%}")
核心技巧总结
| 要点 | 说明 |
|---|---|
| 时间对齐 | 只能用比赛日期之前的数据计算球队状态 |
| 友谊赛折扣 | 给友谊赛特征乘以权重(如0.3~0.6),降低噪音 |
| 分类型统计 | 正式赛/友谊赛分开做特征,再融合 |
| 动机特征 | 加"是否临近大赛"等标志,捕捉友谊赛投入度 |
| 对手强度 | 用Elo评分修正对手质量:Elo变化 × 是否友谊赛 |
| 样本增广 | 友谊赛可扩大样本量,缓解冷启动 |
进阶方向
- 泊松回归预测比分:对进球数建模,友谊赛用小λ惩罚
- Elo体系融合:K因子对友谊赛设置更低(如20 vs 正式赛40)
- 深度学习:用LSTM序列建模球队近期轨迹
- 多任务学习:同时预测胜平负+进球数
如果你能提供具体数据格式(字段名)和预测目标(胜平负/比分/进球数),我可以给出针对性的完整代码。