高位逼抢夺回球权次数
下面用 Python 演示如何统计"高位逼抢(High Press)成功夺回球权"的次数,这是足球数据分析中常见的场景(如 StatsBomb、Wyscout 数据)。

场景说明
定义"高位逼抢夺回球权"的条件:
- 事件类型为
Ball Recovery(夺回球权) - 发生位置在前场(x 坐标 > 60,以 0-100 为球场长度)
- 更严格可加上:由对方半场发起逼抢(近 5 秒内有防守对抗/施压)
示例数据
import pandas as pd
# 模拟事件数据(简化版)
data = {
"event_id": range(1, 16),
"team": ["A"]*8 + ["B"]*7,
"player": ["P1","P2","P3","P4","P5","P6","P7","P8",
"Q1","Q2","Q3","Q4","Q5","Q6","Q7"],
"event_type": [
"Ball Recovery","Ball Recovery","Pass","Ball Recovery",
"Ball Recovery","Shot","Ball Recovery","Ball Recovery",
"Ball Recovery","Pass","Ball Recovery","Ball Recovery",
"Ball Recovery","Ball Recovery","Pass"
],
"x": [72, 55, 30, 85, 78, 90, 40, 65,
70, 45, 88, 62, 33, 76, 50],
"y": [20, 40, 50, 10, 30, 45, 60, 25,
15, 55, 35, 70, 20, 50, 40],
"minute": [3, 7, 10, 15, 22, 25, 30, 35,
40, 45, 50, 55, 60, 70, 80]
}
df = pd.DataFrame(data)
print(df.head())
核心统计逻辑
# 定义高位逼抢区域阈值
HIGH_PRESS_X = 60 # 前场 40% 区域
HIGH_PRESS_Y = (0, 100)
def is_high_press_recovery(row):
"""判断是否为高位逼抢成功夺回球权"""
return (
row["event_type"] == "Ball Recovery"
and row["x"] >= HIGH_PRESS_X
and HIGH_PRESS_Y[0] <= row["y"] <= HIGH_PRESS_Y[1]
)
# 标记事件
df["is_high_press_recovery"] = df.apply(is_high_press_recovery, axis=1)
# 按球队统计
stats = (
df.groupby("team")
.agg(
total_recoveries=("event_type", lambda s: (s == "Ball Recovery").sum()),
high_press_recoveries=("is_high_press_recovery", "sum")
)
)
stats["high_press_rate"] = (
stats["high_press_recoveries"] / stats["total_recoveries"]
).round(2)
print(stats)
输出示例:
total_recoveries high_press_recoveries high_press_rate
team
A 6 3 0.50
B 5 3 0.60
进阶:结合"施压事件"判定真正的逼抢
单一 Ball Recovery 位置高不代表是"逼抢"造成的,可结合 Pressure / Duel 事件:
# 若数据里含 Pressure 事件,可判断:夺回球权前 5 秒内本队有施压
def count_press_recoveries(df, team, window_sec=5):
team_df = df[(df["team"] == team) & (df["event_type"] == "Ball Recovery")]
press_df = df[(df["team"] == team) & (df["event_type"] == "Pressure")]
count = 0
for _, rec in team_df.iterrows():
if rec["x"] < HIGH_PRESS_X: # 位置不满足前场
continue
# 是否存在 5 秒内的施压事件(以 minute 粗粒度模拟,实际用秒级 timestamp)
recent_press = press_df[
(press_df["minute"] >= rec["minute"] - window_sec/60)
& (press_df["minute"] <= rec["minute"])
]
if not recent_press.empty:
count += 1
return count
print("A 队真正的高位逼抢夺回球权:", count_press_recoveries(df, "A"))
print("B 队真正的高位逼抢夺回球权:", count_press_recoveries(df, "B"))
可视化
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 4))
hp = df[df["is_high_press_recovery"]]
ax.scatter(df["x"], df["y"], c="lightgray", label="其他事件")
ax.scatter(hp["x"], hp["y"], c="red", s=80, label="高位逼抢夺回")
ax.axvline(HIGH_PRESS_X, color="blue", linestyle="--", label="前场分界线 x=60")
ax.set_xlim(0, 100); ax.set_ylim(0, 100)
ax.set_xlabel("x (0→100 进攻方向)"); ax.set_ylabel("y")
ax.legend(); ax.set_title("高位逼抢夺回球权分布")
plt.show()
关键要点总结
| 环节 | 说明 |
|---|---|
| 定位事件 | Ball Recovery(夺回球权) |
| 判定前场 | x >= 60(可按联赛/球队自定义) |
| 过滤逼抢 | 结合 Pressure / Duel 事件,时间窗口 3~5 秒 |
| 统计维度 | 按球队 / 球员 / 半场分组 |
| 进阶指标 | 高位夺回率 = 高位夺回次数 / 总夺回次数 |
💡 实战建议:真实数据(如 StatsBomb)字段为
location,timestamp,type,team,player,只需把 x 坐标的归一化比例换算成实际米数(球场 105m)即可适配。
需要我根据你手上的真实数据字段(如 StatsBomb JSON、Wyscout CSV)写一段适配代码吗?可以把字段名发我。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播