统计高位逼抢夺回球权次数
下面用 Python 演示如何根据比赛事件数据统计球队高位逼抢(High Press)成功夺回球权的次数。

场景定义
- 高位逼抢:在对方半场(x > 50,即距对方球门较近的区域),防守球员主动施压
- 成功夺回球权:逼抢后导致对手丢球,本队获得球权
- 我们需要统计符合条件的次数
模拟数据
import pandas as pd
# 模拟比赛事件数据(简化版)
data = {
"event_id": range(1, 16),
"team": ["A","B","A","A","B","A","A","B","A","A","B","A","B","A","A"],
"event_type": [
"press", # 逼抢
"pass",
"press",
"tackle_win", # 抢断成功
"press",
"press",
"interception",# 拦截
"pass",
"press",
"recovery", # 夺回球权
"press",
"press",
"shot",
"press",
"tackle_win",
],
"x": [80, 40, 75, 78, 30, 85, 70, 45, 90, 88, 25, 82, 60, 76, 72], # 场地坐标x(0~100)
"y": [30, 50, 40, 35, 60, 20, 55, 45, 30, 25, 70, 50, 55, 45, 40],
"success": [True, True, True, True, True, True, True, True,
True, True, True, True, True, True, True],
"result": [
"no_possession_change","completed",
"no_possession_change","won",
"no_possession_change","no_possession_change",
"won","completed",
"no_possession_change","won",
"no_possession_change","no_possession_change",
"goal","no_possession_change","won",
],
}
df = pd.DataFrame(data)
print(df)
核心统计逻辑
关键点:逼抢动作 + 在对方半场 + 成功夺回球权,三者同时满足才算一次。
# 定义"夺回球权"的事件结果类型
POSSESSION_WON = {"won", "interception", "recovery", "tackle_win"}
# 统计函数
def count_high_press_recoveries(df, team="A", press_x_threshold=50):
"""
统计某队高位逼抢成功夺回球权的次数
条件:
1. event_type == 'press' (逼抢动作)
2. x > 50 (在对方半场 = 高位)
3. result 属于夺回球权类型 (成功)
"""
mask = (
(df["team"] == team)
& (df["event_type"] == "press")
& (df["x"] > press_x_threshold)
& (df["result"].isin(POSSESSION_WON))
& (df["success"] == True)
)
return df[mask]
# 统计 A 队
press_recoveries_A = count_high_press_recoveries(df, team="A")
print(f"A队高位逼抢成功夺回球权次数: {len(press_recoveries_A)}")
print(press_recoveries_A[["event_id","x","y","result"]])
# 统计 B 队
press_recoveries_B = count_high_press_recoveries(df, team="B")
print(f"B队高位逼抢成功夺回球权次数: {len(press_recoveries_B)}")
print(press_recoveries_B[["event_id","x","y","result"]])
输出示例:
A队高位逼抢成功夺回球权次数: 2
event_id x y result
1 4 78 35 won
3 10 88 25 won
B队高位逼抢成功夺回球权次数: 0
进阶:按区域细分统计
把对方半场划分为三个进攻三区,统计各区逼抢夺回次数:
import numpy as np
def zone(x):
if x <= 50:
return "本方半场"
elif x <= 75:
return "中场三区(50-75)"
else:
return "进攻三区(75-100)"
df["zone"] = df["x"].apply(zone)
mask_press = (
(df["team"] == "A")
& (df["event_type"] == "press")
& (df["x"] > 50)
& (df["result"].isin(POSSESSION_WON))
)
result = (
df[mask_press]
.groupby("zone")
.size()
.reset_index(name="高位逼抢夺回次数")
)
print(result)
完整可运行版(含可视化)
import matplotlib.pyplot as plt
# 解决中文显示
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
zones = ["中场三区(50-75)", "进攻三区(75-100)"]
counts = [
len(press_recoveries_A[press_recoveries_A["x"] <= 75]),
len(press_recoveries_A[press_recoveries_A["x"] > 75]),
]
plt.bar(zones, counts, color=["#4C72B0", "#DD8452"])"A队高位逼抢夺回球权区域分布")
plt.ylabel("次数")
plt.show()
实际项目中的注意事项
| 要点 | 说明 |
|---|---|
| 数据源 | 常见有 StatsBomb、Wyscout、Opta,事件字段名不同(如 pressure、ball_recovery) |
| 坐标转换 | 不同数据源坐标尺度不同(0-100 或 0-120),需统一归一化 |
| "逼抢"判定 | 有时需结合 counterpress 或逼抢后 N 秒内夺回 |
| 时间窗口法 | 逼抢动作后 5 秒内出现 ball_recovery,才算"逼抢导致"的夺回 |
| 多名防守球员 | 可统计"一次逼抢涉及人数",衡量逼抢强度 |
时间窗口法示例(更严谨)
# 假设有 timestamp 列(秒)
df["timestamp"] = df["event_id"] * 3 # 模拟,每事件间隔3秒
recoveries = df[(df["team"]=="A") & (df["result"].isin(POSSESSION_WON))]
presses = df[(df["team"]=="A") & (df["event_type"]=="press") & (df["x"]>50)]
count = 0
for _, p in presses.iterrows():
# 逼抢后 5 秒内出现夺回球权
window = recoveries[
(recoveries["timestamp"] >= p["timestamp"]) &
(recoveries["timestamp"] <= p["timestamp"] + 5)
]
if not window.empty:
count += 1
print(f"逼抢后5秒内夺回球权次数: {count}")
如果你有真实的比赛数据(CSV / API),把字段名告诉我,我可以帮你把上述代码适配到你的数据结构上。