python案例如何量化防守反击的效率值?

wen python案例 1

Python案例:量化防守反击效率值

核心思路

防守反击效率 = 从获得球权到完成射门的转化质量 ÷ 消耗的时间/资源

python案例如何量化防守反击的效率值?

常见量化维度:

  1. 转换速度:夺回球权后多久完成射门
  2. 推进距离:反击推进的纵向距离
  3. 转化率:反击次数 → 射门 → 进球的漏斗
  4. 威胁值:用 xG(预期进球)加权

数据准备

假设有事件数据(类似 StatsBomb / Opta 格式):

import pandas as pd
import numpy as np
# 模拟一场比赛的事件数据
data = {
    'event_id': range(1, 21),
    'team': ['A','A','A','A','A','A','A','A','A','A',
             'A','A','A','A','A','A','A','A','A','A'],
    'type': ['ball_recovery','pass','carry','pass','carry','shot',
             'ball_recovery','pass','carry','pass','carry','pass','shot',
             'ball_recovery','pass','carry','pass','shot',
             'ball_recovery','pass'],
    'minute': [5,5,5,5,5,5, 20,20,20,20,20,20,20,
               35,35,35,35,35, 50,50],
    'second': [10,12,14,16,18,20, 30,32,35,37,39,41,43,
               5,7,9,11,13, 20,22],
    'x': [30,40,55,70,80,92, 25,35,50,65,75,85,94,
          20,35,55,70,90, 28,45],
    'y': [40,42,45,48,50,50, 30,32,35,40,45,48,52,
          50,52,55,50,48, 45,47],
    'end_x': [40,55,70,80,92,92, 35,50,65,75,85,94,94,
              35,55,70,90,90, 45,60],
    'end_y': [42,45,48,50,50,50, 32,35,40,45,48,52,52,
              52,55,50,48,48, 47,50],
    'xg': [0,0,0,0,0,0.35, 0,0,0,0,0,0,0.55,
           0,0,0,0,0.12, 0,0],
}
df = pd.DataFrame(data)

定义反击序列

规则:从 ball_recovery 开始,到 shot / 丢失球权 / 超过 N 秒结束。

def extract_counter_attacks(df, max_duration=15, min_progress=30):
    """
    提取防守反击序列
    max_duration: 反击最大时长(秒)
    min_progress: 最小推进距离(米)才算反击
    """
    counters = []
    i = 0
    events = df.to_dict('records')
    while i < len(events):
        if events[i]['type'] == 'ball_recovery':
            seq = [events[i]]
            start_x = events[i]['x']
            for j in range(i+1, len(events)):
                seq.append(events[j])
                # 计算时间差
                t0 = seq[0]['minute']*60 + seq[0]['second']
                t1 = events[j]['minute']*60 + events[j]['second']
                duration = t1 - t0
                # 终止条件
                if events[j]['type'] == 'shot':
                    progress = events[j]['x'] - start_x
                    if progress >= min_progress and duration <= max_duration:
                        counters.append({
                            'start_second': t0,
                            'duration': duration,
                            'start_x': start_x,
                            'end_x': events[j]['x'],
                            'progress': progress,
                            'n_passes': sum(1 for e in seq if e['type']=='pass'),
                            'n_carries': sum(1 for e in seq if e['type']=='carry'),
                            'xg': events[j]['xg'],
                            'result': 'shot'
                        })
                    break
                if duration > max_duration:
                    break
        i += 1
    return pd.DataFrame(counters)
counter_df = extract_counter_attacks(df)
print(counter_df)

输出示例

   start_second  duration  start_x  end_x  progress  n_passes  n_carries   xg  result
0           310         8      30     92        62         2         2  0.35    shot
1          1230        12      25     94        69         3         2  0.55    shot
2          2105         8      20     90        70         2         2  0.12    shot

计算反击效率值

方法1:加权效率(推荐)

def counter_efficiency(counters, total_recoveries):
    """
    效率公式:
    CE = Σ(xG) / 反击次数 × 速度因子 × 成功因子
    """
    n = len(counters)
    if n == 0:
        return 0
    # 1. 转化为进球的期望
    total_xg = counters['xg'].sum()
    # 2. 速度因子:越快越高效(8秒为基准)
    speed_factor = (8 / counters['duration'].clip(lower=4)).mean()
    speed_factor = min(speed_factor, 2.0)  # 上限
    # 3. 转化率(获得球权后能形成反击的比例)
    conversion_rate = n / total_recoveries
    # 4. 反击效率值
    ce = (total_xg / n) * speed_factor * conversion_rate * 100
    return {
        'counter_count': n,
        'avg_duration': counters['duration'].mean(),
        'avg_progress': counters['progress'].mean(),
        'total_xg': total_xg,
        'speed_factor': round(speed_factor, 2),
        'conversion_rate': round(conversion_rate, 2),
        'counter_efficiency': round(ce, 2)
    }
result = counter_efficiency(counter_df, total_recoveries=4)
print(result)

输出

{
  'counter_count': 3,
  'avg_duration': 9.33,
  'avg_progress': 67.0,
  'total_xg': 1.02,
  'speed_factor': 1.13,
  'conversion_rate': 0.75,
  'counter_efficiency': 28.8
}

方法2:反击 xT 值(进阶)

用位置价值代替 xG,衡量推进威胁:

# 简化的场区价值表(x:0-100, y:0-50 划分)
def position_value(x, y):
    """越靠近对方球门价值越高"""
    if x < 40: return 0.01
    if x < 60: return 0.03
    if x < 80: return 0.08
    if x < 90: return 0.15
    return 0.30
def counter_xt_efficiency(counters):
    """计算反击过程中创造的位置价值总和 / 时长"""
    results = []
    for _, row in counters.iterrows():
        # 用 start_x 到 end_x 的价值提升
        dv = position_value(row['end_x'], 25) - position_value(row['start_x'], 25)
        # 每秒创造价值
        rate = dv / row['duration']
        results.append({
            'start_sec': row['start_second'],
            'threat_gain': dv,
            'per_second': rate,
            'total_xt': dv * 90  # 归一化
        })
    return pd.DataFrame(results)
xt_df = counter_xt_efficiency(counter_df)
print(xt_df)
print(f"\n平均每秒威胁增长: {xt_df['per_second'].mean():.4f}")

可视化(可选)

import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 1. 反击时长分布
axes[0].bar(range(len(counter_df)), counter_df['duration'], color='steelblue')
axes[0].set_title('反击时长 (秒)')
axes[0].set_xlabel('反击编号')
# 2. 推进距离
axes[1].bar(range(len(counter_df)), counter_df['progress'], color='coral')
axes[1].set_title('推进距离 (米)')
axes[1].set_xlabel('反击编号')
# 3. xG 对比
axes[2].bar(range(len(counter_df)), counter_df['xg'], color='green')
axes[2].set_title('每次反击的 xG')
axes[2].set_xlabel('反击编号')
plt.tight_layout()
plt.savefig('counter_efficiency.png', dpi=100)
plt.show()

关键公式总结

指标 公式 含义
平均反击时长 Σduration / N 越低越高效
平均推进距离 Σprogress / N 越高越有威胁
反击转化率 N_shot / N_recovery 抓住机会的能力
速度因子 8 / avg_duration 反击快慢
反击效率值 (avg_xG) × speed × rate × 100 综合评分

实战建议

  1. 数据源:StatsBomb Open Data、FBref、Wyscout 都能提供事件流
  2. 防守反击识别:结合 ball_recovery + counterpress 标签更准确
  3. 对手强度归一化:强弱队对抗时用联赛平均作为基准
  4. 样本量:单场样本太少,建议整赛季聚合(≥30次反击才有统计意义)
  5. 进阶模型:可用 VAEPxT 框架替换简单 xG

如果你有真实的事件数据(CSV 或 StatsBomb JSON),我可以帮你把这段代码改成直接读取的版本。

上一篇综合实时python案例,控球率转化有效吗?

下一篇当前分类已是最新一篇

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