python案例如何量化球队战意指数?

wen python案例 1

量化球队战意指数 - Python 案例分析

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

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 构建层次贝叶斯模型,考虑主场/客场、联赛位置等分组效应,得到每个球队的后验战意分布(而非单一数值),更适合高风险决策。

注意事项

  1. 战意 ≠ 实力:应作为实力评分模型的修正因子(如乘以 0.85~1.15 的系数),而非独立预测指标。
  2. 避免数据泄漏:赛程、伤病必须以赛前信息为准。
  3. 联赛差异大:英超圣诞魔鬼赛程、意甲末轮默契球现象,需分联赛校准权重。
  4. 主观球队:教练轮换习惯、俱乐部财务危机等难以量化,可用专家标注作为先验。

需要我针对特定联赛(如中超/英超) 或某场比赛给出具体的数值演示吗?

抱歉,评论功能暂时关闭!