本文目录导读:

我来为您提供一个完整的Python案例,演示如何利用友谊赛数据做预测,这里以足球友谊赛为例:
数据准备与加载
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
import warnings
warnings.filterwarnings('ignore')
# 创建示例友谊赛数据
np.random.seed(42)
n_matches = 500
data = {
'home_team_rank': np.random.randint(1, 50, n_matches), # 主队排名
'away_team_rank': np.random.randint(1, 50, n_matches), # 客队排名
'home_win_rate': np.random.uniform(0.3, 0.8, n_matches), # 主队近期胜率
'away_win_rate': np.random.uniform(0.3, 0.8, n_matches), # 客队近期胜率
'home_avg_goals': np.random.uniform(0.5, 3.0, n_matches), # 主队场均进球
'away_avg_goals': np.random.uniform(0.5, 3.0, n_matches), # 客队场均进球
'home_avg_conceded': np.random.uniform(0.5, 2.5, n_matches), # 主队场均失球
'away_avg_conceded': np.random.uniform(0.5, 2.5, n_matches), # 客队场均失球
'stadium_advantage': np.random.choice([0, 1], n_matches, p=[0.3, 0.7]), # 主场优势
'weather': np.random.choice(['sunny', 'rainy', 'cloudy'], n_matches), # 天气
'match_importance': np.random.choice(['high', 'medium', 'low'], n_matches) # 比赛重要程度
}
df = pd.DataFrame(data)
# 模拟比赛结果 (1=主队胜, 0=平局, -1=客队胜)
def generate_results(row):
home_strength = (100 - row['home_team_rank']) * 0.3 + row['home_win_rate'] * 10 + \
row['home_avg_goals'] * 2 - row['home_avg_conceded'] * 1.5
away_strength = (100 - row['away_team_rank']) * 0.3 + row['away_win_rate'] * 10 + \
row['away_avg_goals'] * 2 - row['away_avg_conceded'] * 1.5
if row['stadium_advantage'] == 1:
home_strength *= 1.2
# 添加天气影响
if row['weather'] == 'rainy':
home_strength *= 0.9
away_strength *= 0.95
diff = home_strength - away_strength + np.random.normal(0, 3)
if diff > 1:
return 1 # 主队胜
elif diff < -1:
return -1 # 客队胜
else:
return 0 # 平局
df['result'] = df.apply(generate_results, axis=1)
特征工程与数据预处理
# 特征工程
df['rank_diff'] = df['home_team_rank'] - df['away_team_rank']
df['win_rate_diff'] = df['home_win_rate'] - df['away_win_rate']
df['goals_diff'] = df['home_avg_goals'] - df['away_avg_goals']
df['conceded_diff'] = df['home_avg_conceded'] - df['away_avg_conceded']
# 编码分类变量
from sklearn.preprocessing import LabelEncoder, StandardScaler
le_weather = LabelEncoder()
le_importance = LabelEncoder()
le_result = LabelEncoder()
df['weather_encoded'] = le_weather.fit_transform(df['weather'])
df['importance_encoded'] = le_importance.fit_transform(df['match_importance'])
df['result_encoded'] = le_result.fit_transform(df['result'])
# 选择特征
features = ['home_team_rank', 'away_team_rank', 'home_win_rate', 'away_win_rate',
'home_avg_goals', 'away_avg_goals', 'home_avg_conceded', 'away_avg_conceded',
'stadium_advantage', 'weather_encoded', 'importance_encoded',
'rank_diff', 'win_rate_diff', 'goals_diff', 'conceded_diff']
X = df[features]
y = df['result_encoded']
# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
print(f"训练集大小: {len(X_train)}")
print(f"测试集大小: {len(X_test)}")
print(f"类别分布:\n{df['result'].value_counts(normalize=True)}")
模型训练与评估
# 随机森林模型
model_rf = RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42)
model_rf.fit(X_train, y_train)
y_pred_rf = model_rf.predict(X_test)
accuracy_rf = accuracy_score(y_test, y_pred_rf)
print(f"随机森林准确率: {accuracy_rf:.3f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred_rf))
# 逻辑回归模型
from sklearn.linear_model import LogisticRegression
model_lr = LogisticRegression(max_iter=1000)
model_lr.fit(X_train, y_train)
y_pred_lr = model_lr.predict(X_test)
accuracy_lr = accuracy_score(y_test, y_pred_lr)
print(f"\n逻辑回归准确率: {accuracy_lr:.3f}")
# XGBoost模型
try:
from xgboost import XGBClassifier
model_xgb = XGBClassifier(n_estimators=100, learning_rate=0.1, random_state=42)
model_xgb.fit(X_train, y_train)
y_pred_xgb = model_xgb.predict(X_test)
accuracy_xgb = accuracy_score(y_test, y_pred_xgb)
print(f"XGBoost准确率: {accuracy_xgb:.3f}")
except:
print("XGBoost未安装,跳过")
特征重要性分析
# 特征重要性
feature_importance = pd.DataFrame({
'feature': features,
'importance': model_rf.feature_importances_
}).sort_values('importance', ascending=False)
plt.figure(figsize=(10, 6))
plt.barh(feature_importance['feature'][:10], feature_importance['importance'][:10])
plt.xlabel('重要性')'特征重要性分析')
plt.tight_layout()
plt.show()
print("Top 10 重要特征:")
print(feature_importance.head(10))
模型预测函数
def predict_match(home_stats, away_stats, stadium_advantage=1, weather='sunny', importance='medium'):
"""
预测比赛结果
home_stats: 主队统计 (排名, 胜率, 场均进球, 场均失球)
away_stats: 客队统计 (排名, 胜率, 场均进球, 场均失球)
"""
# 构建特征向量
home_rank, home_win_rate, home_goals, home_conceded = home_stats
away_rank, away_win_rate, away_goals, away_conceded = away_stats
# 计算衍生特征
rank_diff = home_rank - away_rank
win_rate_diff = home_win_rate - away_win_rate
goals_diff = home_goals - away_goals
conceded_diff = home_conceded - away_conceded
# 编码分类变量
weather_map = {'sunny': 0, 'rainy': 1, 'cloudy': 2}
importance_map = {'high': 2, 'medium': 1, 'low': 0}
# 创建特征向量
features_list = [home_rank, away_rank, home_win_rate, away_win_rate,
home_goals, away_goals, home_conceded, away_conceded,
stadium_advantage, weather_map[weather], importance_map[importance],
rank_diff, win_rate_diff, goals_diff, conceded_diff]
# 标准化
features_scaled = scaler.transform([features_list])
# 预测概率
prediction = model_rf.predict(features_scaled)
probabilities = model_rf.predict_proba(features_scaled)
# 结果映射
result_map = {0: '客队胜', 1: '平局', 2: '主队胜'} # 注意实际映射
# 根据le_result的映射调整
decoded_result = le_result.inverse_transform(prediction)[0]
return {
'prediction': decoded_result,
'probabilities': probabilities[0],
'confidence': np.max(probabilities[0])
}
可视化结果
# 预测概率可视化
def plot_prediction_probabilities(model, sample_index=0):
X_sample = X_test[sample_index:sample_index+1]
y_true = y_test[sample_index]
proba = model.predict_proba(X_sample)[0]
plt.figure(figsize=(8, 4))
plt.bar(['客队胜', '平局', '主队胜'], proba, color=['red', 'yellow', 'green'])
plt.ylabel('概率')
plt.title(f'预测概率分布 (实际结果: {le_result.inverse_transform([y_true])[0]})')
plt.ylim(0, 1)
for i, p in enumerate(proba):
plt.text(i, p + 0.01, f'{p:.2%}', ha='center')
plt.tight_layout()
plt.show()
plot_prediction_probabilities(model_rf)
# 混淆矩阵
from sklearn.metrics import confusion_matrix
import itertools
def plot_confusion_matrix(cm, classes, title='Confusion Matrix'):
plt.figure(figsize=(8, 6))
plt.imshow(cm, interpolation='nearest', cmap='Blues')
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)
thresh = cm.max() / 2
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], 'd'),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.ylabel('真实标签')
plt.xlabel('预测标签')
plt.tight_layout()
plt.show()
cm = confusion_matrix(y_test, y_pred_rf)
plot_confusion_matrix(cm, classes=['客队胜', '平局', '主队胜'])
实际预测示例
# 预测示例
print("="*50)
print("友谊赛预测示例")
print("="*50)
# 示例:强队主场 vs 弱队客场
home_team = (5, 0.75, 2.1, 1.0) # 排名5,胜率75%,场均进球2.1,场均失球1.0
away_team = (35, 0.45, 1.2, 1.8) # 排名35,胜率45%,场均进球1.2,场均失球1.8
result = predict_match(home_team, away_team, stadium_advantage=1, weather='sunny', importance='high')
print(f"\n强队主场 vs 弱队客场:")
print(f"预测结果: {result['prediction']}")
print(f"置信度: {result['confidence']:.2%}")
# 示例:实力相当的中立场地
home_team = (15, 0.60, 1.5, 1.2)
away_team = (18, 0.58, 1.4, 1.3)
result = predict_match(home_team, away_team, stadium_advantage=0, weather='cloudy', importance='low')
print(f"\n实力相当的中立场地:")
print(f"预测结果: {result['prediction']}")
print(f"置信度: {result['confidence']:.2%}")
模型保存与部署
import joblib
# 保存模型和预处理对象
joblib.dump(model_rf, 'friendly_match_model.pkl')
joblib.dump(scaler, 'scaler.pkl')
joblib.dump(le_weather, 'weather_encoder.pkl')
joblib.dump(le_importance, 'importance_encoder.pkl')
joblib.dump(le_result, 'result_encoder.pkl')
print("模型和预处理器已保存")
# 加载模型(生产环境使用)
def load_models():
model = joblib.load('friendly_match_model.pkl')
scaler = joblib.load('scaler.pkl')
le_weather = joblib.load('weather_encoder.pkl')
le_importance = joblib.load('importance_encoder.pkl')
le_result = joblib.load('result_encoder.pkl')
return model, scaler, le_weather, le_importance, le_result
- 数据质量:友谊赛数据可能包含噪音,需要定期更新和清洗
- 特征工程:合理构造的特征比单纯使用原始数据更有效
- 模型选择:随机森林通常表现不错,但可以尝试多种模型对比
- 过拟合风险:友谊赛样本可能有限,注意使用交叉验证
- 实际应用:预测结果应结合实时数据和专家判断
这个案例演示了从数据准备到模型部署的完整流程,您可以根据实际数据调整特征和模型参数。