本文目录导读:

- 目录导读
- 引言:为什么长短传比例是战术分析的“X光片”?
- 数据准备:从原始比赛事件到结构化DataFrame
- 核心算法:基于距离阈值与方向向量的长短传判定逻辑
- 分布可视化:直方图、箱线图与累积分布函数(CDF)的联合解读
- 进阶洞察:不同阵型、球队风格与比赛时段的比例差异
- SEO问答环节:针对“比例分布”的五大高频问题精解
- 完整代码仓库与运行建议
Python案例实战:统计长短传比例分布,洞悉传球策略的量化密码
目录导读
- 引言:为什么长短传比例是战术分析的“X光片”?
- 数据准备:从原始比赛事件到结构化DataFrame
- 核心算法:基于距离阈值与方向向量的长短传判定逻辑
- 分布可视化:直方图、箱线图与累积分布函数(CDF)的联合解读
- 进阶洞察:不同阵型、球队风格与比赛时段的比例差异
- SEO问答环节:针对“比例分布”的五大高频问题精解
- 完整代码仓库与运行建议
引言:为什么长短传比例是战术分析的“X光片”?
在足球数据分析领域,长短传比例并非简单的数字游戏,而是球队比赛哲学的直接投影,控球型球队(如曼城、巴萨)往往呈现“短传主导、长传辅助”的分布,而防反型球队(如马竞)则反之,通过Python对比赛事件流(Event Stream)进行挖掘,我们不仅能回答“该队长传占比是多少”,更能回答“这个比例在不同场景下如何动态迁移”,本案例将采用公开的StatsBomb或Wyscout示例数据,以python pandas + matplotlib + scipy构建一套可复用的统计管线。
数据准备:从原始比赛事件到结构化DataFrame
我们需要一个包含pass事件的JSON或CSV文件,典型字段包括:x(起点横坐标)、y(起点纵坐标)、end_x(终点横坐标)、end_y(终点纵坐标)、outcome(成功/失败)、team、minute。
import pandas as pd
import json
# 加载数据(示例结构)
with open('match_events.json') as f:
raw = json.load(f)
passes = []
for ev in raw:
if ev['type']['name'] == 'Pass':
passes.append({
'team': ev['team']['name'],
'x': ev['location'][0],
'y': ev['location'][1],
'end_x': ev['pass']['end_location'][0],
'end_y': ev['pass']['end_location'][1],
'minute': ev['minute'],
'height': ev['pass'].get('height', {}).get('name', 'Ground')
})
df = pd.DataFrame(passes)
print(df.head())
清洗关键点:剔除后场安全球(如门将短传)会扭曲比例,建议设置最小推进距离阈值(如>15米才算有效长传)。
核心算法:基于距离阈值与方向向量的长短传判定逻辑
长短传的界定需结合欧氏距离与垂直推进距离,纯距离法简单,但会误将边路横向转移视为长传,更科学的是“组合规则”:
- 欧氏距离
d = sqrt((end_x - x)^2 + (end_y - y)^2) - 纵向推进距离
dy = end_y - y(假设y轴为进攻方向) - 判定标准:若
d >= 25米且dy >= 10米,标记为Long;否则为Short。
import numpy as np
df['distance'] = np.sqrt((df['end_x'] - df['x'])**2 + (df['end_y'] - df['y'])**2)
df['prog_dist'] = df['end_y'] - df['y']
def classify_pass(row):
if row['distance'] >= 25 and row['prog_dist'] >= 10:
return 'Long'
else:
return 'Short'
df['pass_type'] = df.apply(classify_pass, axis=1)
统计比例:
ratio = df['pass_type'].value_counts(normalize=True) * 100 print(ratio)
分布可视化:直方图、箱线图与累积分布函数(CDF)的联合解读
单单一个比例数字不够立体,我们需要看分布形态。
- 直方图:显示传球距离的密度分布,长传为主的队会出现“双峰”——一个短传峰(10-20米),一个长传峰(35-50米)。
- 箱线图:按球队分组,观察传球距离中位数、四分位距,中位数高说明该队偏好直接打法。
- CDF曲线:横轴为距离,纵轴为“传球距离≤该值的概率”,CDF在70%位置对应的距离越短,说明短传占比越高。
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots(1, 3, figsize=(15, 5))
# 直方图
sns.histplot(data=df, x='distance', hue='pass_type', bins=30, ax=ax[0])
ax[0].set_title('传球距离分布')
# 箱线图按队
sns.boxplot(data=df, x='team', y='distance', ax=ax[1])
ax[1].set_title('球队传球距离箱线图')
# CDF
from scipy.stats import ecdf
res = ecdf(df['distance'])
ax[2].plot(res.cdf.quantiles, res.cdf.probabilities)
ax[2].set_title('累积分布函数')
进阶洞察:不同阵型、球队风格与比赛时段的比例差异
- 比赛时段:将比赛分为0-15, 15-30, ..., 75-90分钟,计算每个时段的长传比例,通常前半场(试探阶段)短传多,最后15分钟(急于扳平或拖延)长传比例飙升。
- 阵型变量:3-5-2阵型倾向于使用翼卫长传转移,而4-3-3更依赖中场短传渗透,可以按球队首发阵型分组计算比例差异。
- 成功长传 vs 失败长传:计算长传成功率(
outcome列),高比例低成功率往往意味着盲目起长传,战术效果差。
# 时段比例
df['period'] = pd.cut(df['minute'], bins=[0,15,30,45,60,75,90], labels=['0-15','15-30','30-45','45-60','60-75','75-90'])
period_ratio = df.groupby('period')['pass_type'].apply(lambda x: (x=='Long').mean()*100)
print(period_ratio)
SEO问答环节:针对“比例分布”的五大高频问题精解
Q1:长传比例多少算“正常”? A1:没有绝对标准,英超2022-2023赛季平均长传占比约17%±5%,但皇马、利物浦等技术流球队仅12%,而伯恩利曾高达29%,关键看战术意图,而非绝对值。
Q2:为什么用“纵向推进距离”而不是单纯用总距离? A2:因为横传或回传距离再长也不具备战术推进意义,纵向推进距离能过滤掉无效横移,更贴近“传球强度”的真实定义。
Q3:统计长短传比例时,要不要排除门将/后卫的短传?
A3:视分析目标而定,若分析控球体系,应排除门将和本方禁区内的倒脚(这些球会稀释短传占比),建议增加area字段过滤。
Q4:如何评估比例分布的“稳定性”? A4:使用变异系数(CV = 标准差/平均值),若某队每场比赛长传比例CV<0.2,说明风格固化;若CV>0.4,则战术变化多端。
Q5:Python代码运行速度慢怎么办?
A5:改用polars或dask处理百万级事件,另外将分类逻辑向量化(用np.where)可提速10倍以上,避免apply循环。
完整代码仓库与运行建议
建议在Jupyter Notebook中分步执行,数据可下载statsbombpy库的内置示例赛事:
pip install statsbombpy
from statsbombpy import sb df = sb.events(match_id=3788741) # 2022世界杯决赛 df = df[df['type']=='Pass'].copy() # 后续处理同上
优化建议:使用vpandas等向量化框架替代原生apply,尤其当数据量超过10万行时,最终输出建议导出为交互式HTML图表(Plotly),便于战术教练直接拖拽查看。
注:本文所有统计逻辑均基于公开数据案例,实际应用中请根据赛事级别调整距离阈值(如青年队可降至20米),希望这篇案例能帮助你在“长短传比例”这个微观指标中,窥见宏观战术的雄图。