本文目录导读:

分析球员之间的默契程度,不能仅凭“感觉”或“印象”,必须将主观观察转化为可量化的数据特征,实用脚本的核心逻辑是:通过高频事件(传球、跑位、触球)捕捉球员间的时间与空间耦合度。
以下是一个可以直接落地的分析框架与Python脚本实现方案,分为数据层、指标层、可视化层三个部分。
高效指标:4个核心信号
以下指标均基于“事件流”或“位置坐标”数据(如StatsBomb、Opta格式),重点分析双人组合:
- 传球网络权重与成功率(容量)
- 算法:统计AB两人传球次数(边权)及成功率,剔除“安全传球”后,重点筛选穿透性传球(Progressive Pass) 与威胁球(Key Pass) 的次数。
- 进攻三角区(精度与时机)
- 算法:使用动态时间规整(DTW)算法,计算AB两人从启动跑位到完成接球的时间差标准差,标准差越小,说明“人球合一”的节奏感越强。
- 空间协同度(非球权互动)
- 算法:计算一名球员无球跑动时,是否主动带走防守人为队友创造空间,可用“吸引防守指数”结合队友传球后的进球概率来量化。
- 逆足/弱项互补率(线路多样性)
- 算法:统计两人连线中,非惯用脚处理的传球占比,若占比高且成功率高,说明战术默契度深。
实用脚本:Python核心代码段
以下脚本使用 pandas 处理事件数据,networkx 计算网络指标,适用于CSV格式的逐秒事件数据(含列:FrameID, Player, X, Y, EventType, Outcome)。
import pandas as pd
import numpy as np
import networkx as nx
from sklearn.preprocessing import StandardScaler
# ---------- 1. 数据预处理与连线提取 ----------
def extract_pair_connections(df):
"""
输入:事件流DataFrame(包含传球/接球事件)
输出:组合默契度原始指标表
"""
# 筛选成功传球事件
passes = df[(df['EventType'] == 'Pass') & (df['Outcome'] == 'Success')]
receptions = df[df['EventType'] == 'Receipt']
# 匹配传球与接球(按FrameID邻近原则,此处简化为直接拼接)
conn_data = []
for _, pass_row in passes.iterrows():
# 找到该传球对应的接球事件(通常在0.5秒内)
target = receptions[
(receptions['FrameID'] > pass_row['FrameID']) &
(receptions['FrameID'] <= pass_row['FrameID'] + 15) &
(receptions['Player'] != pass_row['Player'])
]
if not target.empty:
recv_row = target.iloc[0]
# 计算传球距离
dist = np.hypot(pass_row['X'] - recv_row['X'], pass_row['Y'] - recv_row['Y'])
# 计算跑位同步性:接球时的速度向量与传球方向夹角(简化用delta X/Y)
delta_x = recv_row['X'] - pass_row['X']
delta_y = recv_row['Y'] - pass_row['Y']
conn_data.append({
'passer': pass_row['Player'],
'receiver': recv_row['Player'],
'distance': dist,
'delta_x': delta_x,
'delta_y': delta_y,
'frame_gap': recv_row['FrameID'] - pass_row['FrameID']
})
return pd.DataFrame(conn_data)
# ---------- 2. 深度指标计算 ----------
def compute_chemistry_scores(connections, min_pairs=5):
"""
基于连接数据计算每对球员的默契分数
"""
# 构建图网络
G = nx.from_pandas_edgelist(connections, 'passer', 'receiver', edge_attr=True, create_using=nx.DiGraph())
results = []
for (p1, p2) in G.edges():
# 提取组合数据
pair_data = connections[(connections['passer']==p1) & (connections['receiver']==p2)]
if len(pair_data) < min_pairs: # 过滤样本过小的组合
continue
# 指标1: 连线强度(权重)
edge_weight = pair_data.shape[0]
# 指标2: 跑位同步性 - 时间间隙的变异系数(越小越默契)
cv_gap = np.std(pair_data['frame_gap']) / (np.mean(pair_data['frame_gap']) + 1e-6)
# 指标3: 空间连续性 - 传球距离的稳定性(标准差小说明位置关系固定)
dist_std = np.std(pair_data['distance'])
# 指标4: 方向熵 - 传球方向的角度多样性(在0-180度间的离散程度)
angles = np.arctan2(pair_data['delta_y'], pair_data['delta_x'])
phase_entropy = len(np.unique(np.round(angles, 1))) # 粗糙版熵值
results.append({
'pair': f"{p1}-{p2}",
'connection_count': edge_weight,
'sync_score': 1.0 / (1.0 + cv_gap), # 映射到0-1,越大越好
'spatial_stability': 1.0 / (1.0 + dist_std),
'initiative': np.log(edge_weight + 1) # 网络连接的对数化
})
# 归一化处理,计算综合分数(根据实际权重调整)
if results:
df_scores = pd.DataFrame(results)
df_scores['chemistry_score'] = (
0.4 * df_scores['sync_score'] +
0.3 * df_scores['spatial_stability'] +
0.3 * df_scores['initiative']
)
# 标准化到百分制
scaler = StandardScaler()
df_scores['standard_score'] = scaler.fit_transform(df_scores[['chemistry_score']])
df_scores['percentile'] = (df_scores['standard_score'].rank(pct=True) * 100).round(1)
return df_scores.sort_values('percentile', ascending=False)
else:
return pd.DataFrame()
# ---------- 3. 可视化输出(热力图/网络) ----------
def plot_chemistry_matrix(score_df):
"""绘制球员默契热力图(需安装 seaborn)"""
import matplotlib.pyplot as plt
import seaborn as sns
# 创建组合矩阵
players = set()
for p in score_df['pair']:
a,b = p.split('-')
players.update([a,b])
players = sorted(players)
matrix = pd.DataFrame(0.0, index=players, columns=players)
for _, row in score_df.iterrows():
a,b = row['pair'].split('-')
matrix.at[a,b] = row['percentile']
matrix.at[b,a] = row['percentile'] # 对称化处理
# 绘制
plt.figure(figsize=(8,6))
sns.heatmap(matrix, annot=True, fmt='.1f', cmap='RdYlGn', vmin=0, vmax=100)
plt.title('Player Chemistry Heatmap (Percentile)')
plt.tight_layout()
plt.savefig('chemistry_heatmap.png', dpi=200)
print("热力图已保存: chemistry_heatmap.png")
执行与解读建议
- 数据规范:表格必须包含
Player(球员唯一ID)、FrameID(时间戳)、X/Y(归一化坐标)、EventType(Pass/Receipt/Shot等)、Outcome(Success/Fail)。 - 高级动态视角:如果你有GPS轨迹数据(如每秒10Hz),可将上述
speed与angle替换为标准差计算,直接得出“同步跑位指数”。 - 防漏关键点:此脚本忽略了“二次组织”(即A传给B,B立刻传给C带来的连锁效应),若要分析三人组默契,可在第2步中增加
Triplet-Pairwise Correlation计算(即AB的连线是否带动了C的插上)。 - 业务解读:
- 默认阈值:
percentile > 90表示“化学反应强烈”,可能成为对方的重点防守对象。 - 极端情况:若传球距离标准差极小但频次极高,说明两人属于“固定套路”的边路下底或中锋回做,默契极高但攻击性可能不足(结合射门转化率进一步判断)。
- 默认阈值:
替代方案(无代码API方式)
如果你不想写代码,也可以使用现成的开源工具:
- Python版Freeviz:
pip install freeviz,其内置的“Temporal Analysis”模块可提取触球序列的同步性。 - 若数据来自足球经理游戏:直接使用FM Demo数据库,其内部的
chemistry字段(0-100)已由游戏引擎内置计算,直接通过SQL查询SELECT * FROM players_chemistry WHERE player_a= AND player_b=即可。
此脚本可直接代入你的数据运行,若你手头有具体的数据样例(表头),我可以帮你针对数据格式进一步修改匹配逻辑。