统计交叉跑位造成威胁次数
下面给你一个可落地的统计方案 + Python 脚本模板,核心思路是:先定义“交叉跑位”和“威胁”的判定规则,再用事件数据或追踪数据自动统计。

先明确判定规则(关键)
什么是交叉跑位?
常见三种定义,选一种或组合:
| 类型 | 定义 | 数据需求 |
|---|---|---|
| A. 位置交叉 | 两名同队球员在短时间内(如2秒内)跑动轨迹相交 | 追踪数据(x,y,t) |
| B. 方向交叉 | 两人跑动方向夹角 > 90°且路径接近 | 追踪数据 |
| C. 事件型 | 传球后接球人穿越防守/队友跑位 | 事件数据 |
什么是“造成威胁”?
- 交叉后 3~5 秒内 出现以下之一:
- 射门
- 关键传球 / 助攻
- 进入禁区
- xG 提升超过阈值(如 +0.05)
- 对方失位 / 犯规
Python 脚本模板(基于追踪数据)
import pandas as pd
import numpy as np
from itertools import combinations
# ========== 参数配置 ==========
CROSS_WINDOW = 2.0 # 交叉判定时间窗(秒)
THREAT_WINDOW = 5.0 # 交叉后威胁判定时间窗(秒)
MIN_DIST = 1.5 # 轨迹相交距离阈值(米)
DIR_ANGLE_THRESH = 90 # 方向夹角阈值(度)
XG_GAIN_THRESH = 0.05 # xG提升阈值
# ========== 读取数据 ==========
# tracking: columns = [frame, time, player_id, team, x, y]
tracking = pd.read_csv("tracking.csv")
def get_player_track(df, pid):
return df[df.player_id == pid].sort_values("time").reset_index(drop=True)
def paths_cross(t1, t2, window=CROSS_WINDOW, min_dist=MIN_DIST):
"""判断两条轨迹在时间窗内是否相交"""
t_start = max(t1.time.min(), t2.time.min())
t_end = min(t1.time.max(), t2.time.max())
for t in np.arange(t_start, t_end, 0.1):
p1 = t1.iloc[(t1.time - t).abs().argmin()]
p2 = t2.iloc[(t2.time - t).abs().argmin()]
if abs(p1.time - t) > 0.2 or abs(p2.time - t) > 0.2:
continue
d = np.hypot(p1.x - p2.x, p1.y - p2.y)
if d < min_dist:
return True, t
return False, None
def directions_opposite(t1, t2, t_cross):
"""判断交叉瞬间两人方向是否对向/交叉"""
def vel(track, t):
i = (track.time - t).abs().argmin()
if i == 0 or i >= len(track) - 1:
return None
dt = track.time.iloc[i+1] - track.time.iloc[i-1]
if dt == 0: return None
vx = (track.x.iloc[i+1] - track.x.iloc[i-1]) / dt
vy = (track.y.iloc[i+1] - track.y.iloc[i-1]) / dt
return np.array([vx, vy])
v1, v2 = vel(t1, t_cross), vel(t2, t_cross)
if v1 is None or v2 is None: return False
cos = np.dot(v1, v2) / (np.linalg.norm(v1)*np.linalg.norm(v2) + 1e-9)
angle = np.degrees(np.arccos(np.clip(cos, -1, 1)))
return angle > DIR_ANGLE_THRESH
# ========== 主流程 ==========
results = []
for team in tracking.team.unique():
team_df = tracking[tracking.team == team]
players = team_df.player_id.unique()
for p1, p2 in combinations(players, 2):
t1, t2 = get_player_track(team_df, p1), get_player_track(team_df, p2)
crossed, t_cross = paths_cross(t1, t2)
if not crossed:
continue
if not directions_opposite(t1, t2, t_cross):
continue
# 检查交叉后威胁窗口内是否有威胁事件
threat = threats[
(threats.team == team) &
(threats.time >= t_cross) &
(threats.time <= t_cross + THREAT_WINDOW)
]
is_threat = (
(threat.event.isin(["shot","key_pass","assist","penalty_area_entry"])).any()
or (threat.xG.diff().max() > XG_GAIN_THRESH)
)
results.append({
"team": team,
"players": f"{p1}-{p2}",
"time": round(t_cross, 1),
"threat": is_threat
})
df_res = pd.DataFrame(results)
print("总交叉跑位次数:", len(df_res))
print("造成威胁次数:", df_res.threat.sum())
print("\n按球队统计:")
print(df_res.groupby("team").threat.agg(["count","sum"]))
如果没有追踪数据(只有事件数据)
用简化版规则:传球事件中,接球人在传球瞬间与另一队友位置交叉,且之后5秒内有射门/关键传球。
# events: [time, team, player, event, x, y, end_x, end_y]
cross_events = []
for _, pass_ in events[events.event == "pass"].iterrows():
t = pass_.time
teammates = events[
(events.team == pass_.team) &
(events.time.between(t-1, t+1)) &
(events.player != pass_.player)
]
for _, mate in teammates.iterrows():
if abs(mate.x - pass_.end_x) < 2 and abs(mate.y - pass_.end_y) < 2:
# 视为跑位交汇点
follow = events[
(events.team == pass_.team) &
(events.time.between(t, t+5)) &
(events.event.isin(["shot","key_pass","assist"]))
]
cross_events.append({
"time": t,
"players": f"{pass_.player}-{mate.player}",
"threat": len(follow) > 0
})
df = pd.DataFrame(cross_events).drop_duplicates(subset=["time","players"])
print(f"交叉跑位形成威胁 {df.threat.sum()} 次 / 共 {len(df)} 次")
输出示例
总交叉跑位次数: 47
造成威胁次数: 12
按球队统计:
count sum
teamA 28 8
teamB 19 4
可扩展优化方向
- 加入防守球员:只有当交叉导致防守错位才算威胁。
- xT / xG 模型:用位置威胁值替代简单事件。
- 可视化:用 mplsoccer 画出交叉轨迹与后续威胁。
- 防误判:加最小间隔时间,排除摆渡、回追。
需要我根据你手上的具体数据格式(StatsBomb / 自家追踪 / Opta)改写成可直接跑的版本吗?告诉我列名和数据来源即可。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播