量化球队战意指数 - Python 案例分析
战意指数(Motivation Index)是体育数据分析中较难量化的指标,但可以通过多维度数据构建,下面给出一个完整的建模思路和 Python 实现。

战意指数建模思路
战意通常来源于以下 6 个维度:
| 维度 | 说明 | 数据来源 |
|---|---|---|
| 排名压力 | 争冠/保级/欧战资格 | 联赛积分榜 |
| 赛程密度 | 是否一周双赛/三天一赛 | 赛程表 |
| 后续赛程 | 下轮是否有更关键比赛(轮换动机) | 赛程表 |
| 伤病停赛 | 主力缺阵情况 | 伤病名单 |
| 历史交锋 | 德比/宿敌情结 | 历史数据 |
| 杯赛/联赛优先级 | 多线作战时的侧重 | 教练言论/赛程 |
核心代码实现
基础数据结构
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 模拟球队数据
teams = pd.DataFrame({
'team': ['A队', 'B队', 'C队', 'D队'],
'points': [58, 45, 30, 20], # 当前积分
'matches_played': [28, 28, 28, 28],
'max_points': [84, 84, 84, 84], # 理论最高积分(剩余场次全胜)
'rank': [1, 3, 6, 8],
'total_teams': [10, 10, 10, 10],
'goals_for': [50, 42, 30, 25],
'goals_against': [20, 28, 40, 48]
})
各维度战意计算函数
def rank_pressure(row, league_type='normal'):
"""排名压力:争冠/保级/欧战资格区附近战意最高"""
rank = row['rank']
total = row['total_teams']
pts = row['points']
max_pts = row['max_points']
score = 0
# 争冠区(前2名且有机会夺冠)
if rank <= 2 and pts >= max_pts * 0.6:
score += 100
# 保级区(倒数3名内)
elif rank >= total - 2:
score += 95
# 欧战区边缘(3-5名)
elif 3 <= rank <= 5:
score += 70
# 中游无欲无求
else:
score += 30
return score
def schedule_density(last_match_date, next_match_date, match_date):
"""赛程密度:与上一场间隔越短,体能消耗越大,战意可能降低"""
days_since_last = (match_date - last_match_date).days
days_to_next = (next_match_date - match_date).days
min_rest = min(days_since_last, days_to_next)
if min_rest <= 2:
return 40 # 极密
elif min_rest == 3:
return 70
else:
return 100
def upcoming_importance(next_opponent_rank, current_team_rank, total_teams):
"""后续赛程重要性:若下轮是关键战,本场可能轮换(战意下调)"""
# 下轮对手是争冠/保级直接对手
if abs(next_opponent_rank - current_team_rank) <= 2 and \
(current_team_rank <= 3 or current_team_rank >= total_teams - 2):
return 60 # 本场留力
return 100
def injury_impact(missing_key_players, total_key_players=11):
"""伤病影响:主力缺阵越多,实际战斗力下降"""
ratio = missing_key_players / total_key_players
return max(0, 100 - ratio * 150)
def derby_factor(opponent, derby_list):
"""德比/宿敌加成"""
return 120 if (opponent,) in derby_list else 100
综合战意指数
def motivation_index(row, context):
"""
row: 球队基础数据
context: {'last_date','next_date','match_date','next_opp_rank',
'missing_players','is_derby'}
"""
r = rank_pressure(row)
s = schedule_density(context['last_date'], context['next_date'], context['match_date'])
u = upcoming_importance(context['next_opp_rank'], row['rank'], row['total_teams'])
i = injury_impact(context['missing_players'])
d = 120 if context['is_derby'] else 100
# 加权(权重可按联赛经验调整)
weights = {'rank': 0.35, 'schedule': 0.15, 'upcoming': 0.15,
'injury': 0.20, 'derby': 0.15}
raw = (r * weights['rank'] +
s * weights['schedule'] +
u * weights['upcoming'] +
i * weights['injury'] +
d * weights['derby'])
# 归一化到 0-100
return round(raw / 1.20, 1)
实际调用示例
match_date = datetime(2024, 4, 15)
context_A = {
'last_date': datetime(2024, 4, 12), # 3天前
'next_date': datetime(2024, 4, 19), # 4天后
'match_date': match_date,
'next_opp_rank': 6,
'missing_players': 2,
'is_derby': True
}
team_A = teams.iloc[0]
mi_A = motivation_index(team_A, context_A)
print(f"{team_A['team']} 战意指数: {mi_A}/100")
批量计算并可视化
import matplotlib.pyplot as plt
results = []
for idx, team in teams.iterrows():
ctx = {
'last_date': datetime(2024, 4, 12),
'next_date': datetime(2024, 4, 19),
'match_date': match_date,
'next_opp_rank': 5,
'missing_players': idx,
'is_derby': idx == 0
}
results.append({'team': team['team'],
'mi': motivation_index(team, ctx)})
df = pd.DataFrame(results).sort_values('mi', ascending=False)
plt.bar(df['team'], df['mi'], color='steelblue')
plt.axhline(60, color='red', linestyle='--', label='临界线')'球队战意指数对比')
plt.ylabel('战意指数')
plt.legend()
plt.show()
进阶优化建议
加入滚动数据(动态权重)
# 用最近5场对手的"战意"产生实际战果,反推球队当前状态
team_form = df_matches.groupby('team')['result'].apply(
lambda x: (x == 'W').astype(int).rolling(5).mean().iloc[-1]
)
用机器学习回归真实战意
将历史比赛结果的特征(排名差、休息天数、伤病、德比等)作为输入,用 XGBoost 或 LogisticRegression 预测胜负概率,模型输出的特征重要性可作为战意权重来源:
from sklearn.linear_model import LogisticRegression features = ['rank_diff', 'rest_days', 'injury_count', 'is_derby', 'points_gap'] X = historical_df[features] y = (historical_df['result'] == 'W').astype(int) model = LogisticRegression().fit(X, y) print(dict(zip(features, model.coef_[0]))) # 系数可反推各维度对胜负的贡献,即"有效战意权重"
贝叶斯更新
用 PyMC 或 pymc-bart 构建层次贝叶斯模型,考虑主场/客场、联赛位置等分组效应,得到每个球队的后验战意分布(而非单一数值),更适合高风险决策。
注意事项
- 战意 ≠ 实力:应作为实力评分模型的修正因子(如乘以 0.85~1.15 的系数),而非独立预测指标。
- 避免数据泄漏:赛程、伤病必须以赛前信息为准。
- 联赛差异大:英超圣诞魔鬼赛程、意甲末轮默契球现象,需分联赛校准权重。
- 主观球队:教练轮换习惯、俱乐部财务危机等难以量化,可用专家标注作为先验。
需要我针对特定联赛(如中超/英超) 或某场比赛给出具体的数值演示吗?