本文目录导读:

“撞墙式配合”在足球数据分析里通常叫 One-Two(二过一),要统计它完成了多少次,需要先明确数据来源和判定标准,因为“撞墙式配合”不是一个标准化事件,不同数据源的定义不同。
下面给你一个可落地的脚本思路和示例代码,你可以根据手头数据调整。
先明确判定逻辑
一次“撞墙式配合完成”通常需要满足:
- 球员A传球给球员B
- 球员B不做停顿/盘带,直接一脚回传给球员A(或A前插后的位置)
- 回传后A成功接到球(配合完成)
- 通常发生在推进方向上,且B的回传是“做墙”
简化判定条件(基于事件数据):
- 事件序列:
Pass(A→B)→Pass(B→A) - 两次传球时间间隔 ≤ 2~3 秒
- 第二次传球是一脚出球(B接球后触球次数 ≤ 1)
- 两次传球方向夹角合理(A→B 与 B→A 大致反向或侧向)
- 最终A成功控球(下一次触球是A)
假设你有的数据格式
以常见的 event data(如 StatsBomb / Opta 风格)为例,每行一个事件:
match_id,period,minute,second,team,player,event_type,pass_recipient,pass_end_x,pass_end_y,start_x,start_y 1,1,10,05,TeamA,PlayerA,pass,PlayerB,60,40,40,30 1,1,10,07,TeamA,PlayerB,pass,PlayerA,45,32,60,40 ...
Python 脚本示例
import pandas as pd
from math import atan2, degrees
# 读取事件数据
df = pd.read_csv("events.csv")
# 只保留传球事件,按时间排序
passes = df[df["event_type"] == "pass"].copy()
passes["time_sec"] = passes["minute"] * 60 + passes["second"]
passes = passes.sort_values(["match_id", "period", "time_sec"]).reset_index(drop=True)
def angle_diff(a1, a2):
"""两个方向角的差值(0~180度)"""
d = abs(a1 - a2) % 360
return min(d, 360 - d)
one_two_count = 0
details = []
# 遍历每个传球,找它后面紧接的传球
for i in range(len(passes) - 1):
p1 = passes.iloc[i]
p2 = passes.iloc[i + 1]
# 同一场比赛、同一阶段、同一球队
if p1["match_id"] != p2["match_id"]: continue
if p1["period"] != p2["period"]: continue
if p1["team"] != p2["team"]: continue
# 条件1:A→B,B→A
if p1["pass_recipient"] != p2["player"]: continue
if p2["pass_recipient"] != p1["player"]: continue
# 条件2:时间间隔 ≤ 3 秒(一脚出球)
dt = p2["time_sec"] - p1["time_sec"]
if dt > 3: continue
# 条件3:方向大致反向(A→B 与 B→A 夹角 > 120°)
ang1 = degrees(atan2(p1["pass_end_y"] - p1["start_y"],
p1["pass_end_x"] - p1["start_x"]))
ang2 = degrees(atan2(p2["pass_end_y"] - p2["start_y"],
p2["pass_end_x"] - p2["start_x"]))
if angle_diff(ang1, ang2) < 120: continue
# 条件4:第二次传球后 A 接到球(下一事件是 A 的触球)
if i + 2 < len(passes):
p3 = passes.iloc[i + 2]
if p3["player"] != p1["player"]: continue
else:
continue
one_two_count += 1
details.append({
"match_id": p1["match_id"],
"minute": p1["minute"],
"player_a": p1["player"],
"player_b": p1["player"],
})
print(f"撞墙式配合完成次数:{one_two_count}")
pd.DataFrame(details).to_csv("one_two_details.csv", index=False)
输出结果
脚本会输出:
- 总次数:
撞墙式配合完成次数:N - 明细表
one_two_details.csv:每场比赛、每分钟、参与的 A/B 球员
需要你确认的几个点
不同数据源判定差异很大,建议你先明确:
| 问题 | 建议 |
|---|---|
| 数据源是什么?(StatsBomb / Opta / Wyscout / 自采集) | 字段名需对应调整 |
| 是否要求“一脚出球”? | 用 dt <= 3s 近似,或看触球数 |
| 是否要求向前推进? | 加 p2.end_x > p2.start_x 或 x 前进条件 |
| 是否要求最终A成功控球? | 看下一事件是否 A 触球 |
| 是否统计“尝试”还是“完成”? | 完成 = 回传后A接到球 |
如果你告诉我你用的数据格式(字段名/样例几行),以及“完成”的判定标准(比如是否要求一脚出球、是否要求向前),我可以把脚本改成直接能跑你数据的版本。