本文目录导读:

这是一个很有意思的问题,在现代足球(篮球、排球等团队项目)分析中,球员之间的“默契”已经从玄学变成了可以量化的“协同行为数据”。
要分析球员之间的默契程度,不能用单一指标,而需要建立一套“行为-结果”分析框架,以下是一份实用脚本的构建指南,分为数据采集、核心算法、实战脚本和可视化四个层面。
第一步:数据采集(你需要什么数据?)
要量化默契,脚本需要依赖事件数据和轨迹数据:
- 事件数据:传球(成功/失败)、接球、射门、抢断、跑位接应。
关键字段:时间戳、球员ID、坐标(x,y)、事件类型、结果(成功/失败)。
- 轨迹数据:每秒25次左右的球员位置追踪。
关键字段:球员ID、帧数、坐标。
- 上下文数据:防守压力(对手距离)、比赛阶段(进攻/防守)、阵型。
第二步:核心算法(如何定义“默契”?)
默契可以分为三个维度:连通性(找得到)、互补性(配合好)、预见性(跑位对)。
你的脚本可以围绕以下核心公式构建:
传球成功率加权指数(连通性)
这是最基础的,但需要加权。
[ \text{Momentum}{A,B} = \frac{\text{成功传球}{A \to B}}{\text{总传球}_{A \to B}} \times \text{防守压力系数} ]
- 进阶:如果A传给B的球在高压力(防守人距离<1米)下依然成功,脚本应给予更高的权重。
预期助攻与创造力(互补性)
使用xG(预期进球)模型的后置版本:xA(预期助攻)。
- 脚本逻辑:如果A球员传给B球员的那一球,B球员形成射门且射门位置/角度极佳(高xG值),说明A和B的进攻配合默契。
跑位与视野共识(预见性/无球默契)—— 推荐
这是最有价值的指标,核心算法是“传球空间比”。
- 逻辑:当A持球,B球员进行了无球跑动(比如前插身后)。
- 脚本计算:B的跑动方向是否与A传球的角度吻合?
- 计算B跑动路线与A出球方向的余弦相似度。
- 如果余弦值接近1(方向完全一致),则记一次“有效接应”。
标准球权转换熵(稳定性)
默契高的组合,失误率低且球权转换有序。
[ \text{Entropy} = -\sum (p_i \log p_i) ]
- 如果A和B之间只有单一的传球模式(比如只会横传),熵值低;如果传球线路多样且高效,熵值适中但成功率高,这代表战术默契。
第三步:实用脚本模板(Python + Pandas)
下面的脚本是一个框架,你可以直接根据数据源修改字段名。
import pandas as pd
import numpy as np
from itertools import combinations
# 假设你有一个DataFrame: events
# 列包括: ['timestamp', 'player_id', 'event_type', 'x', 'y', 'next_player_id', 'outcome']
# event_type: 'pass', 'reception', 'shot'
# outcome: 'success', 'fail'
def calculate_pair_synergy(events_df, min_samples=5):
"""
计算所有二人组合的默契度指标
"""
results = []
# 只保留传球相关的数据
passes = events_df[(events_df['event_type'] == 'pass')].copy()
# 获取所有球员
players = sorted(set(passes['player_id']) | set(passes['next_player_id']))
for p1, p2 in combinations(players, 2):
# 筛选A->B 和 B->A 的传球
ab_passes = passes[(passes['player_id'] == p1) & (passes['next_player_id'] == p2)]
ba_passes = passes[(passes['player_id'] == p2) & (passes['next_player_id'] == p1)]
total_ab = len(ab_passes)
total_ba = len(ba_passes)
# 确保有足够样本
if (total_ab + total_ba) < min_samples:
continue
# --- 指标1: 双向成功率 ---
success_ab = len(ab_passes[ab_passes['outcome'] == 'success'])
success_ba = len(ba_passes[ba_passes['outcome'] == 'success'])
combined_success_rate = (success_ab + success_ba) / (total_ab + total_ba) if (total_ab + total_ba) > 0 else 0
# --- 指标2: 进攻威胁性 (传球向前推进距离) ---
# 计算传球的向前传球距离 (y轴通常代表进攻方向)
forward_distance = []
for _, row in ab_passes.iterrows():
if row['outcome'] == 'success':
# 假设你能找到接球点的坐标,此处用 next_event_x/y 代替
dist = row.get('next_y', row['y']) - row['y'] # 简化示例
forward_distance.append(max(dist, 0))
avg_forward_progress = np.mean(forward_distance) if forward_distance else 0
# --- 指标3: 跑动默契 (假设你有轨迹数据,此处用事件替代) ---
# 简化:传球后,接球者形成射门的比例
shots_after = passes[(passes['player_id'] == p1) & (passes['next_player_id'] == p2) & (passes['next_event_type'] == 'shot')]
creativity = len(shots_after) / total_ab if total_ab > 0 else 0
# --- 综合评分 (需要根据你的需求调整权重) ---
synergy_score = (combined_success_rate * 0.4 +
np.tanh(avg_forward_progress / 10) * 0.3 +
creativity * 0.3)
results.append({
'pair': f'{p1}-{p2}',
'total_passes': total_ab + total_ba,
'success_rate': combined_success_rate,
'forward_progress': avg_forward_progress,
'creativity': creativity,
'synergy_score': synergy_score
})
# 生成排名表
synergy_df = pd.DataFrame(results)
synergy_df = synergy_df.sort_values('synergy_score', ascending=False)
return synergy_df
# 使用示例
# df = pd.read_csv('your_match_events.csv')
# synergy_rank = calculate_pair_synergy(df)
# print(synergy_rank.head(10))
第四步:进阶脚本与可视化(热力图)
如果你有坐标数据,可以绘制“连线热力图”,这比数字更直观。
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.collections import LineCollection
def plot_synergy_network(events_df, top_n=5):
"""
绘制球员传球默契网络
"""
# 获取场地尺寸
pitch_length, pitch_width = 105, 68
fig, ax = plt.subplots(figsize=(12, 8))
# 画球场 (简化)
ax.add_patch(mpatches.Rectangle((0, 0), pitch_length, pitch_width,
edgecolor='black', facecolor='none'))
# 计算球员平均位置
positions = events_df.groupby('player_id')[['x', 'y']].mean()
# 绘制传球线 (厚线代表高默契)
for p1, p2 in combinations(positions.index, 2):
ab = events_df[(events_df['player_id'] == p1) & (events_df['next_player_id'] == p2)]
ba = events_df[(events_df['player_id'] == p2) & (events_df['next_player_id'] == p1)]
total = len(ab) + len(ba)
if total > 5: # 过滤低频率
linewidth = min(total / 5.0, 10) # 线粗代表传球多
alpha = min((len(ab[ab['outcome']=='success']) + len(ba[ba['outcome']=='success'])) / total, 1.0) * 0.7
ax.plot([positions.loc[p1, 'x'], positions.loc[p2, 'x']],
[positions.loc[p1, 'y'], positions.loc[p2, 'y']],
'b-', linewidth=linewidth, alpha=alpha)
# 绘制球员节点
ax.scatter(positions['x'], positions['y'], s=100, c='red', zorder=5)
for idx, row in positions.iterrows():
ax.annotate(idx, (row['x'], row['y']), textcoords="offset points",
xytext=(0,5), ha='center', fontweight='bold')
# 标题解释
plt.title('传球默契网络图 (线越粗 = 互动越多 | 透明度越高 = 成功率越高)')
plt.axis('off')
plt.show()
第五步:注意事项与纠偏
在写脚本时,防止被数据误导,建议加入以下过滤逻辑:
- 对手强度校准:如果A和B面对弱队时配合紧密,面对强队时则不然,那么他们只是“顺风局默契”,脚本应引入对手排名加权。
- 剔除“垃圾时间”:大比分领先后的传球效率极高,这属于无效默契,脚本应只统计比赛处于比分胶着(如±1球)的时间段。
- 位置动态:很多高分组合是固定套路(如定位球战术),并非真正的运动战默契,如果要评估全场景默契,应排除定位球事件。
一个实用的默契分析脚本,核心是“数据降维”,通过上述Python脚本,你可以将场上22人(约231个组合)的复杂交互,降维成一张“默契排名表”和一张“传球网络图”。
你可以从最基础的“传球成功率 + 频率”开始,仅用公开的赛事统计数据(如Wyscout或StatsBomb的免费样本数据),写一个脚本运行起来,再逐步加入坐标和防守压力数据,你的分析就会越来越接近足球经理游戏和真实球队分析师的水平了。