7.6 构造示例③:量化伤停折损与阵容完整度
构造示例「主力缺阵」是分析中最模糊的变量。这一篇把它变成数字。
一、三个必须量化的维度
| 维度 | 含义 | 数据来源 |
|---|---|---|
| 球员贡献度 | 这名球员对球队有多重要 | 球员高阶指标、出场时间 |
| 替补落差 | 替代者与主力的差距 | 阵容数据、球员指标 |
| 位置关键度 | 这个位置的战术重要性 | 领域知识 + 数据验证 |
二、第一步:量化球员贡献度
方法一:出场时间占比(最粗糙但可用)
def minutes_share(player_minutes, team_total_minutes):
"""球员出场时间占球队总时间的比例,衡量基础重要性"""
if team_total_minutes <= 0:
return 0.0
return player_minutes / team_total_minutes
问题:它无法区分「很重要的球员」和「只是出场多」。
方法二:进球参与贡献度(进阶)
def goal_involvement(goals, assists, team_goals):
"""进球参与度:球员参与的进球占球队总进球的比重"""
if team_goals <= 0:
return 0.0
return (goals + assists) / team_goals
问题:只反映进攻贡献,忽略了防守型球员。
方法三:综合贡献分(推荐)
def contribution_score(player, team):
"""综合贡献分:把出场时间与产出一并考虑
player: 含 minutes_share / goal_involvement / advanced_score 的字典
team : 球队层面的基准值,用于归一化
"""
# 三项子指标,各自归一到 0~1 后加权平均
w_time = player.get('minutes_share', 0) or 0
w_goal = min(1.0, player.get('goal_involvement', 0) or 0)
w_adv = player.get('advanced_score', 0) or 0 # 高阶指标,已归一到 0~1
# 权重可按位置调整(见下一节)
return 0.4 * w_time + 0.3 * w_goal + 0.3 * w_adv
关于高阶指标的使用:
球小策提供的球员高阶指标覆盖面广、颗粒度细,非常适合作为这一层的输入。
你完全可以直接用它作为advanced_score,而不必自己从基础统计重构一个。
这就是「用 API 拿原料 + 自己建模型」的分工。
三、第二步:按位置区分权重
不同位置的关键度不同:
| 位置 | 关键度系数(教学参考值) | 说明 |
|---|---|---|
| 门将 | 高 | 单独用门将指标评估 |
| 中后卫 | 高 | 防线组织核心 |
| 单后腰 | 最高 | 攻防转换枢纽,影响面最广 |
| 组织型中场 | 高 | 进攻发起 |
| 中锋 | 高(若为唯一支点) | 进攻体系核心 |
| 边锋 | 中 | 通常有轮换方案 |
| 边后卫 | 中低 | 影响相对可控 |
POSITION_WEIGHT = {
'GK': 1.15,
'DF': 1.05,
'DM': 1.30, # 单后腰单独提升
'MF': 1.10,
'FW': 1.15,
'W': 0.90, # 边锋通常有轮换
'FB': 0.85, # 边后卫
}
def weighted_loss(player, position):
"""单名球员缺阵造成的损失权重"""
base = contribution_score(player, None)
w = POSITION_WEIGHT.get(position, 1.0)
return base * w
注意:上表的系数是教学参考值。你应该用你自己的数据做验证——用什么方法见 7.9。
四、第三步:计算阵容完整度
def squad_integrity(players, unavailable_ids):
"""阵容完整度:1 减去缺阵球员损失占比之和"""
# 全队贡献总和(作为分母)
total = sum(contribution_score(p, None) * POSITION_WEIGHT.get(p.get('position', 'MF'), 1.0)
for p in players)
if total <= 0:
return {'integrity': 1.0, 'loss_detail': []}
loss = 0.0
detail = []
for p in players:
if p.get('id') in unavailable_ids:
w = contribution_score(p, None) * POSITION_WEIGHT.get(p.get('position', 'MF'), 1.0)
loss += w
detail.append({
'name': p.get('name'),
'position': p.get('position'),
'loss_ratio': round(w / total, 4),
})
# 限制下界,防止极端情况给出负值或接近 0 的无意义值
integrity = max(0.4, 1.0 - loss / total)
return {'integrity': round(integrity, 3), 'loss_detail': detail}
五、第四步:按位置修正对应的指标
最关键的一点:不要把完整度当作一个统一乘数。不同位置缺阵,影响的是不同指标。
| 缺阵位置 | 应修正的指标 |
|---|---|
| 锋线核心 | 下调进攻强度实时指数 |
| 中场组织核心 | 下调中场创造力指标 |
| 单后腰 / 中后卫 | 下调防守强度实时指数 |
| 门将 | 单独按门将指标差距修正 |
def apply_injury_adjustment(base_metrics, loss_detail):
"""按缺阵位置分别修正对应指标"""
adj = dict(base_metrics) # 复制一份,不修改原对象
for item in loss_detail:
pos = item.get('position')
ratio = item.get('loss_ratio', 0)
# 用 1 - 损失比例 作为折扣系数
factor = 1.0 - min(0.5, ratio * 2) # 单项损失最多打五折
if pos in ('FW', 'W'):
adj['attack_index'] = adj.get('attack_index', 0) * factor
elif pos in ('MF', 'DM'):
adj['creativity_index'] = adj.get('creativity_index', 0) * factor
elif pos in ('DF', 'GK'):
adj['defense_index'] = adj.get('defense_index', 0) * factor
return adj
六、一个必须说明的限制
所有系数都是经验值,需要你自己验证。
上表中的位置权重、0.4/0.3/0.3 的分配、折扣上限 0.5,都属于教学起点。
正确做法是:用历史数据回测,看哪组参数对「缺阵后的实际表现变化」拟合得最好。
这正是「权重怎么定」要解决的问题 → 7.8。
七、三个实战注意点
- 「出战成疑」要分两种情形评估,不要取中间值;
- 注意轮换与伤病是两回事:没有伤病不等于全主力出战;
- 注意赛季初样本不足:新赛季前几轮,球员贡献度指标还不稳定。
足球赛事前瞻 | AI 智能分析 | 足球数据解读 - 球小策