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

wen python案例 6

统计高位逼抢夺回球权次数

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

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

场景定义

  • 高位逼抢:在对方半场(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),把字段名告诉我,我可以帮你把上述代码适配到你的数据结构上。

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