python案例统计高位逼抢夺回球权几次?

wen python案例 1

高位逼抢夺回球权次数

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

python案例统计高位逼抢夺回球权几次?

场景说明

定义"高位逼抢夺回球权"的条件:

  1. 事件类型为 Ball Recovery(夺回球权)
  2. 发生位置在前场(x 坐标 > 60,以 0-100 为球场长度)
  3. 更严格可加上:由对方半场发起逼抢(近 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)写一段适配代码吗?可以把字段名发我。

上一篇python案例认为哪些指标最值得重点关注?

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

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

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝