量化防守反击效率值的Python实践
防守反击(Counter-Attack)是足球、篮球等运动中的重要战术,下面我从指标定义 → 数据建模 → Python实现 → 可视化完整讲解。

效率值的理论定义
防守反击效率 = 反击产出 / 反击投入
核心指标拆分
| 维度 | 指标 | 说明 |
|---|---|---|
| 触发 | 反击次数 | 由守转攻的次数 |
| 速度 | 转换耗时 | 断球到射门的时间 |
| 推进 | 传球次数/推进距离 | 越少越快越好 |
| 产出 | 射门/进球/xG | 最终威胁 |
| 成功率 | 形成射门的比例 | 效率核心 |
推荐公式
反击效率值 (CAE) = (进球×1.0 + 射正×0.5 + 射门×0.2) / 反击次数
× 速度系数
速度系数 = 1 + (基准时间 - 实际转换时间) / 基准时间
数据准备
假设我们从事件数据中提取每次反击的片段(如 StatsBomb、Opta 格式):
import pandas as pd
import numpy as np
# 模拟一次反击事件序列
data = {
'match_id': [1,1,1, 2,2,2, 3,3,3],
'counter_id': [101,101,101, 102,102,102, 103,103,103],
'event_type': ['tackle','pass','shot']*3,
'timestamp': [10,14,20, 30,33,40, 55,58,70], # 秒
'x': [30,55,85, 40,60,80, 20,45,75], # 进攻方向坐标
'outcome': ['success','success','goal',
'success','success','saved',
'success','fail','blocked']
}
df = pd.DataFrame(data)
计算反击效率
def calc_counter_efficiency(df, base_time=15):
"""
计算每支球队/每场比赛的防守反击效率
base_time: 基准转换时间(秒),用于速度系数
"""
results = []
for cid, grp in df.groupby('counter_id'):
grp = grp.sort_values('timestamp')
start_t = grp['timestamp'].iloc[0]
end_t = grp['timestamp'].iloc[-1]
duration = end_t - start_t
# 推进距离(从首次触球到终点的 x 位移)
progress = grp['x'].iloc[-1] - grp['x'].iloc[0]
# 产出判定
final = grp.iloc[-1]
goal = 1 if final['outcome'] == 'goal' else 0
on_target = 1 if final['outcome'] in ['goal','saved'] else 0
shot = 1 if final['event_type'] == 'shot' else 0
# 传球次数
passes = (grp['event_type'] == 'pass').sum()
# 速度系数:越快越高
speed_factor = 1 + (base_time - duration) / base_time
speed_factor = max(speed_factor, 0.5) # 防止为负
# 单次反击产出分
output = goal*1.0 + on_target*0.5 + shot*0.2
# 单次反击效率
efficiency = output * speed_factor
results.append({
'counter_id': cid,
'duration': duration,
'progress': progress,
'passes': passes,
'goal': goal,
'shot': shot,
'efficiency': efficiency,
'speed_factor': speed_factor
})
return pd.DataFrame(results)
eff_df = calc_counter_efficiency(df)
print(eff_df)
输出示例:
counter_id duration progress passes goal shot efficiency speed_factor
0 101 10 55 1 1 1 1.50 1.33
1 102 10 40 1 0 1 0.93 1.33
2 103 15 55 1 0 1 0.70 1.00
团队整体效率值
def team_counter_rating(eff_df, total_counters=None):
"""把单次效率聚合为球队效率值(0-100)"""
if total_counters is None:
total_counters = len(eff_df)
total_eff = eff_df['efficiency'].sum()
success_rate = eff_df['shot'].mean() # 形成射门比例
goal_rate = eff_df['goal'].sum() / total_counters
# 加权综合(可自行调参)
rating = (total_eff * 10 + success_rate * 40 + goal_rate * 60)
return min(rating, 100)
rating = team_counter_rating(eff_df)
print(f"防守反击效率值: {rating:.1f} / 100")
进阶:加入 xG 模型
如果使用真实数据,可用 shot xG 替代简单产出:
# 假设每条反击有 xG 累积
eff_df['xg'] = [0.35, 0.10, 0.05] # 示例
def xg_efficiency(row, base_time=15):
speed = max(1 + (base_time - row['duration'])/base_time, 0.5)
# 单位时间 xG 产出
return row['xg'] / max(row['duration'], 1) * 100 * speed
eff_df['xg_eff'] = eff_df.apply(xg_efficiency, axis=1)
可视化对比
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# 各次反击效率
axes[0].bar(eff_df['counter_id'].astype(str), eff_df['efficiency'], color='steelblue')
axes[0].set_title('各次反击效率值')
axes[0].set_xlabel('反击ID'); axes[0].set_ylabel('效率值')
# 时间 vs 效率(散点)
axes[1].scatter(eff_df['duration'], eff_df['efficiency'], s=100, c='crimson')
axes[1].set_title('转换时间 vs 效率')
axes[1].set_xlabel('转换耗时(秒)'); axes[1].set_ylabel('效率值')
plt.tight_layout()
plt.savefig('counter_efficiency.png', dpi=120)
plt.show()
关键设计要点
- 归一化:不同比赛反击次数不同,需做 z-score 或 min-max 归一,方便跨队对比。
- 权重可调:进球、射正、射门的权重应根据战术偏好调整(如"快反"重速度,"阵地反"重质量)。
- 对手强度修正:可用对手防守评级做除数修正。
- 样本量要求:单场样本太小(3–8 次反击),建议按赛季或按联赛跨场聚合。
完整可运行封装
class CounterAttackEvaluator:
def __init__(self, base_time=15, weights=(1.0, 0.5, 0.2)):
self.base_time = base_time
self.w_goal, self.w_on, self.w_shot = weights
def evaluate(self, df):
df = df.sort_values(['counter_id','timestamp'])
rows = []
for cid, g in df.groupby('counter_id'):
dur = g['timestamp'].iloc[-1] - g['timestamp'].iloc[0]
last = g.iloc[-1]
goal = int(last['outcome']=='goal')
on = int(last['outcome'] in ['goal','saved'])
shot = int(last['event_type']=='shot')
speed = max(1 + (self.base_time - dur)/self.base_time, 0.5)
score = (goal*self.w_goal + on*self.w_on + shot*self.w_shot) * speed
rows.append({'counter_id':cid,'duration':dur,'score':score})
return pd.DataFrame(rows)
调用:
evaluator = CounterAttackEvaluator(base_time=15) print(evaluator.evaluate(df))
如果你有具体的比赛数据源(StatsBomb / Opta / 自己标注的视频),我可以帮你改成对应字段的解析代码,或加入 xG、对手强度修正的版本,要不要接着做跨球队排行榜对比?