哪队更高效?
下面我用一个足球比赛数据分析的案例,演示如何统计两队的"反击次数"并比较哪队反击更高效,反击通常定义为:在本方半场夺回球权后,快速推进到对方半场并形成射门。

案例背景
假设我们有一份比赛事件数据(类似 StatsBomb 格式),字段包括:时间、球队、事件类型、位置(x, y 坐标)、是否射门等。
完整代码实现
import pandas as pd
import numpy as np
# ============ 1. 构造示例数据 ============
np.random.seed(42)
events = []
teams = ['A队', 'B队']
event_types = ['抢断', '传球', '带球', '射门', '丢球']
# x坐标 0-100,0为本方球门,100为对方球门
for i in range(500):
team = np.random.choice(teams)
etype = np.random.choice(event_types, p=[0.15, 0.5, 0.15, 0.1, 0.1])
x = np.random.uniform(0, 100)
y = np.random.uniform(0, 100)
minute = np.random.randint(1, 90)
events.append([i, minute, team, etype, x, y])
df = pd.DataFrame(events, columns=['id', 'minute', 'team', 'event_type', 'x', 'y'])
df = df.sort_values(['minute', 'id']).reset_index(drop=True)
# ============ 2. 定义反击检测逻辑 ============
def detect_counter_attacks(df, time_window=15, x_gain_threshold=40):
"""
识别反击:
1. 在本方半场(x < 50)夺回球权(抢断/丢球后获得)
2. 在 time_window 秒/事件内,球推进超过 x_gain_threshold
3. 最终形成射门(x > 80 且 event_type == '射门')
"""
counter_attacks = []
for idx, row in df.iterrows():
# 只关注在本方半场的夺球事件
if row['event_type'] in ['抢断'] and row['x'] < 50:
start_x = row['x']
start_minute = row['minute']
team = row['team']
# 查看之后的 time_window 个事件
window = df.iloc[idx+1 : idx+1+time_window]
team_events = window[window['team'] == team]
if len(team_events) == 0:
continue
max_x = team_events['x'].max()
# 判断是否形成射门
shots = team_events[(team_events['event_type'] == '射门') &
(team_events['x'] > 80)]
x_gain = max_x - start_x
if x_gain >= x_gain_threshold:
counter_attacks.append({
'team': team,
'start_minute': start_minute,
'start_x': start_x,
'end_x': max_x,
'x_gain': x_gain,
'led_to_shot': len(shots) > 0,
'led_to_goal': len(shots) > 0 and np.random.rand() < 0.2 # 模拟转化
})
return pd.DataFrame(counter_attacks)
# ============ 3. 执行统计 ============
ca_df = detect_counter_attacks(df)
# 按球队汇总
summary = ca_df.groupby('team').agg(
反击次数=('team', 'count'),
平均推进距离=('x_gain', 'mean'),
射门转化数=('led_to_shot', 'sum'),
).reset_index()
summary['射门转化率'] = summary['射门转化数'] / summary['反击次数']
summary['效率评分'] = summary['射门转化率'] * summary['平均推进距离']
print("=== 反击效率对比 ===")
print(summary.round(3).to_string(index=False))
# 判断哪队更高效
best_team = summary.loc[summary['效率评分'].idxmax(), 'team']
print(f"\n🏆 反击最高效的球队:{best_team}")
核心指标解读
| 指标 | 含义 | 越高越好? |
|---|---|---|
| 反击次数 | 符合反击定义的次数 | 看情况(多不一定好) |
| 平均推进距离 | 每次反击推进的x坐标距离 | |
| 射门转化率 | 反击最终形成射门的比例 | |
| 效率评分 | 转化率 × 平均推进距离 | ✅ 综合指标 |
关键设计要点
-
反击定义要明确:不是所有抢断都算反击,必须"由守转攻 + 快速推进 + 形成威胁"。
-
时间窗口:用
time_window=15个事件限制反击的"快速"特性,避免把阵地战误算成反击。 -
空间阈值:
x_gain_threshold=40确保有实质推进,而不是原地倒脚。 -
综合效率评分:单纯比次数不公平(打防反的队次数多),应该看每次反击的产出质量。
如果要换成其他场景
这个模板很好迁移,
- 篮球:抢断后 → 快攻 → 得分
- 电竞(如 CS/LOL):抓单/反打 → 拿资源 → 团队收益
- 商业:竞品降价后 → 快速响应 → 夺回市场份额
只需要修改 detect_counter_attacks 函数里的触发条件和成功判据即可。
需要我针对某个具体运动(足球/篮球)或真实数据集(如 StatsBomb 开放数据)做更精确的实现吗?