本文目录导读:

- 第一部分:核心评估模型(KPI定义)
- 第二部分:实用脚本逻辑(Python伪代码 & 结构)
- 第三部分:更实用的“一手数据”获取法(无数据源)
- 第四部分:实战案例演示(假设数据)
- 第五部分:注意事项(避坑指南)
评估教练的“换人得分能力”(即通过替补球员改变比赛走势、直接贡献进球或助攻的能力),是一项非常专业且需要数据建模的工作,它不能只看“换上去的人进了几个球”,而必须排除“球队本来就会赢”的干扰。
这里提供一个实战向、可落地的评估框架和脚本逻辑,分为量化数据模型和脚本实现思路两部分。
第一部分:核心评估模型(KPI定义)
要“科学”评估,必须建立预期值(Baseline),我们用以下五个核心指标来构建评估体系:
-
净胜球影响率(Net Goal Impact, NGI)
- 公式:
(替补登场后球队进球数 - 替补登场后球队丢球数) - (该球员未登场时球队同期平均净胜球) - 逻辑: 假设某队全场平均每30分钟净胜0.2球,但某教练在60分钟换上A后,最后30分钟净胜1.0球,则A的NGI为+0.8。
- 公式:
-
直接参与效率(Direct Involvement per 90, DI90)
- 公式:
(替补上场后贡献的进球 + 助攻) / 替补上场总分钟数 * 90 - 逻辑: 这是最原始的冲击力数据,排除了首发球员体能充沛期的数据干扰。
- 公式:
-
战术执行力(XG Differential / 实际进球 vs 预期进球)
- 公式:
替补登场后球队实际进球数 - 替补登场后球队预期进球数(xG) - 逻辑: 如果换人后进球了,但xG极低(如远射或神仙球),说明这属于球员个人能力(灵光一现),而非教练战术安排,我们用这个差值来区分“高质量得分机会”和“个人英雄主义”。
- 公式:
-
换人时点决策系数(Timing Coefficient, TC)
- 公式:
(比赛剩余时间 / 90) * 比分状态权重 - 权重建议:
- 落后时换人:权重1.5
- 平局时换人:权重1.2
- 领先时换人:权重0.8
- 逻辑: 在落后时换人进球的难度远大于领先时,该系数用于修正难度偏差。
- 公式:
-
逆转/绝杀贡献值(Comeback Points, CP)
- 若替补上场后,球队由“平/负”转为“胜”,或者在85分钟后打入扳平/绝杀球,额外加分。
- 逻辑: 这是“大心脏”属性,也是教练临场指挥最高光的体现。
第二部分:实用脚本逻辑(Python伪代码 & 结构)
以下脚本用于处理历史比赛数据,输出教练的换人得分评分卡。
import pandas as pd
import numpy as np
# 假设你有一张DataFrame(events),包含以下字段:
# match_id, minute, event_type(goal/assist/sub_on/sub_off/red_card), player_in, team_goal_diff(换人时球队净胜球数), is_away, xg_added(该次进攻的xG)
def evaluate_sub_scoring(events_df):
results = {}
# 1. 筛选所有换人事件
subs = events_df[events_df['event_type'] == 'sub_on'].copy()
for _, sub in subs.iterrows():
match_id = sub['match_id']
sub_minute = sub['minute']
player_in = sub['player_in']
# 获取该球员下场后的剩余比赛时间段数据(简化处理,按时间倒推)
# --- 核心计算逻辑 ---
# 1. 计算该球员登场后的球队表现(过滤出比赛时间 >= sub_minute 的事件)
after_sub = events_df[(events_df['match_id'] == match_id) &
(events_df['minute'] >= sub_minute) &
# 排除掉对手的进球(需要判断事件归属)
(events_df['team'] == sub['team'])]
# 计算该球员登场后球队的进球数、丢球数
goals_for = len(after_sub[after_sub['event_type'] == 'goal'])
goals_against = ... # 对进攻球
# 2. 计算该球员直接参与(进球或助攻算1,造点等映射)
direct_involve = after_sub.apply(lambda x: 1 if x['player'] == player_in and x['event_type'] in ['goal','assist'] else 0, axis=1).sum()
# 3. 获取该场比赛的全局基准线(例如全场平均30分钟净胜球)
baseline_df = events_df[events_df['match_id'] == match_id]
# 简单粗暴:用全场平均作为基准
global_gf = len(baseline_df[baseline_df['event_type'] == 'goal'])
global_ga = ...
avg_net_per_min = (global_gf - global_ga) / 90
# 4. 计算预期净胜球(用于排除运气)
xg_after = after_sub['xg_added'].sum() / (90 - sub_minute) * 90
# 5. 计算综合得分(示例权重)
# 实际净胜时间比
net_effect = (goals_for - goals_against) - avg_net_per_min * (90 - sub_minute)
# 战术价值:实际进球 - 预期进球
tactical_value = (goals_for - xg_after) if goals_for > 0 else 0
# 6. 难度系数(比分状态)
score_diff_at_sub = sub['team_goal_diff']
if score_diff_at_sub < 0: # 落后
difficulty = 1.4
elif score_diff_at_sub == 0: # 平局
difficulty = 1.2
else:
difficulty = 0.9
# 汇总到该球员(或该教练的名下)
score = (direct_involve * 2) + (net_effect * 1.0) + (tactical_value * 1.5)
final_score = score * difficulty
results[(match_id, player_in)] = final_score
# 聚合到教练维度(需要sub表有coach字段)
return pd.DataFrame(results.items(), columns=['key', 'score']).groupby('coach').mean()
第三部分:更实用的“一手数据”获取法(无数据源)
如果你没有专业的数据API(如Opta、StatsBomb),可以用抓取公开文字直播/赛后统计的方式,编写一个简化版脚本:
- 输入:直接从懂球帝、Whoscored等网站复制比赛事件文本(如:“,第60分钟,换人,9号张三上,7号李四下”)。
- 脚本处理:
- 用正则表达式提取:分钟、替换球员名字、当时的比分。
- 记录该球员上场后,到比赛结束(或下一次换人)期间发生的射正、进球事件。
- 计算“每一百分钟换人贡献指数” = (该球员登场后的球队进球数 2 - 丢球数 1.5) / 登场时间。
第四部分:实战案例演示(假设数据)
假设我们统计了某教练在2024赛季的12次换人:
| 比赛 | 换人时比分(我方-对方) | 换人时间 | 登场球员 | 登场后球队进/丢球(至结束) | XG差值 |
|---|---|---|---|---|---|
| 对A队 | 0-1(落后) | 60' | 前锋X | 进2球,丢0球 | +1.2 |
| 对B队 | 1-1(平局) | 70' | 中场Y | 进0球,丢0球 | -0.1 |
| 对C队 | 2-0(领先) | 65' | 前锋Z | 进1球,丢1球 | +0.5 |
脚本输出评分结果:
- 对A队:落后+逆转 → 难度1.4,净胜+2,直接参与2球 → 得分极高(9.8分)
- 对B队:平局+换人无效果 → 净胜0,XG-0.1 → 得分低(1.2分)
- 对C队:领先+锦上添花 → 难度0.9,净胜0(进1丢1) → 得分中等(3.1分)
最终该教练的“平均换人得分能力”为: (9.8 + 1.2 + 3.1) / 3 ≈ 4.7分
第五部分:注意事项(避坑指南)
- 排除“红牌”干扰:如果换人是因为有人被罚下,数据应剔除,否则会严重低估教练的换人能力。
- 对手质量加权:如果面对的是曼城或皇马,和面对保级队的换人得分,含金量完全不同,建议脚本里加入
对手排名权重(对手排名1-3名,系数1.3;保级队系数0.7)。 - 区分“教练要求”还是“球员自主”:数据无法完全体现,但若该球员上场后的大部分进球来源于定位球设计或边路传中战术(这些属于教练安排),则权重应高于单骑闯关的个人进球。
如果你需要更加具体的Python爬虫脚本去抓取特定网站的换人数据,或者需要一个Excel版本的自动计算表模板,可以告诉我你的数据源格式,我来帮你定制。