统计交叉跑位造成威胁次数
下面给你一个可直接运行的 Python 脚本模板,用于统计足球/篮球等比赛中「交叉跑位造成威胁」的次数,你可以根据实际数据源(视频标注、追踪数据、事件日志)替换输入部分。

先定义“交叉跑位造成威胁”的判定规则
因为不同项目定义不同,脚本里把规则参数化:
| 条件 | 说明 | 参数 |
|---|---|---|
| 两名进攻球员轨迹交叉 | 距离小于阈值 | cross_dist=2.0 米 |
| 交叉发生在危险区域 | 如禁区前沿/禁区 | zone 区域 |
| 交叉后 3 秒内形成威胁 | 射门/关键传球/进入禁区 | threat_window=3.0 秒 |
| 防守球员被吸引/失位 | 防守距离变化 | defender_pull=1.5 米 |
只有 1+2+3(可选 4)同时满足,才计一次“威胁”。
脚本(基于追踪数据 DataFrame)
假设你有逐帧追踪数据,字段如下:
frame, time, player_id, team, x, y
import pandas as pd
import numpy as np
from itertools import combinations
# ============ 参数配置 ============
CROSS_DIST = 2.0 # 两人距离小于2米算交叉
CROSS_ANGLE = 30 # 轨迹夹角(度)突变阈值,可选
THREAT_WINDOW = 3.0 # 交叉后3秒内
ZONE_X = (70, 105) # 危险区域 x 范围(进攻方向)
ZONE_Y = (20, 48) # 危险区域 y 范围
DEFENDER_PULL = 1.5 # 防守被拉开距离
# ============ 读取数据 ============
df = pd.read_csv("tracking.csv")
df = df.sort_values(["frame", "player_id"])
# ============ 工具函数 ============
def in_danger_zone(x, y):
return ZONE_X[0] <= x <= ZONE_X[1] and ZONE_Y[0] <= y <= ZONE_Y[1]
def dist(a, b):
return np.hypot(a[0]-b[0], a[1]-b[1])
# ============ 主逻辑 ============
events = [] # 记录所有交叉事件
threat_count = 0 # 威胁次数
frames = sorted(df["frame"].unique())
for i, f in enumerate(frames):
cur = df[df["frame"] == f]
# 只看进攻方
attackers = cur[cur["team"] == "attack"]
defenders = cur[cur["team"] == "defend"]
# 两两组合检查交叉
for p1, p2 in combinations(attackers.itertuples(), 2):
d = dist((p1.x, p1.y), (p2.x, p2.y))
if d > CROSS_DIST:
continue
# 是否在危险区域
if not (in_danger_zone(p1.x, p1.y) or in_danger_zone(p2.x, p2.y)):
continue
# 检查交叉后 THREAT_WINDOW 秒内的威胁事件
t0 = p1.time
future = df[(df["time"] > t0) & (df["time"] <= t0 + THREAT_WINDOW)]
threat = False
# 示例:未来窗口内有人进入禁区或射门
for r in future.itertuples():
if r.team == "attack" and in_danger_zone(r.x, r.y):
threat = True
break
# 可选:防守被吸引
if threat and len(defenders) > 0:
min_def_dist = min(dist((p1.x, p1.y), (d.x, d.y))
for d in defenders.itertuples())
if min_def_dist > DEFENDER_PULL:
pass # 记录用,不强制
if threat:
threat_count += 1
events.append({
"frame": f,
"time": t0,
"player1": p1.player_id,
"player2": p2.player_id,
"x": p1.x, "y": p1.y
})
# ============ 输出 ============
print(f"交叉跑位造成威胁次数: {threat_count}")
print(pd.DataFrame(events))
输出示例
交叉跑位造成威胁次数: 7
frame time player1 player2 x y
0 320 8.2 9 11 82.3 30.1
1 415 10.6 11 7 88.5 28.4
...
如果你没有追踪数据,只有事件日志
可以用更简单的版本——人工/半自动标注:
import pandas as pd
# 事件表: time, type, player, x, y, note
events = pd.read_csv("events.csv")
# 找出 “交叉跑位” 且 note 含 “威胁” 的事件
threats = events[
(events["type"] == "cross_run") &
(events["note"].str.contains("威胁", na=False))
]
print(f"交叉跑位造成威胁次数: {len(threats)}")
print(threats)
想更准?可以加这些增强项
- 轨迹夹角:用前后几帧算速度向量,夹角 > 30° 才算真交叉。
- 防守反应:交叉后防守球员重心偏移 > 1.5 米。
- xG/威胁值:交叉后 3 秒内 xG 增量 > 0.05。
- 可视化:用 matplotlib 画出交叉点 + 威胁路径。
如果你告诉我:
- 项目是足球还是篮球?
- 数据是视频、追踪、还是手工事件表?
- 危险区域怎么定义?
我可以帮你把脚本改成直接能跑你数据的版本。