本文目录导读:

- 案例背景
- 步骤 1:模拟或读取数据
- 步骤 2:定义进攻三区并过滤数据
- 步骤 3:计算传球成功率
- 步骤 4:进阶分析(可选,增加实战意义)
- 步骤 5:可视化(建议)
- 可能遇到的常见问题及解决(针对Python案例)
针对你提到的“进攻三区传球成功率”这一数据指标,结合Python的体育数据分析(特别是足球分析)案例,我们可以从数据获取、数据清洗、核心计算逻辑、可视化四个维度来拆解这个案例。
由于你没有提供具体的原始数据格式(例如是来自StatsBomb、WyScout的XML/JSON,或者是手动整理的CSV),我为你构建一个通用的、可运行的Python分析案例,并附带核心代码解释。
案例背景
- 定义:进攻三区通常指球场上距离对方球门约35-40米以内的区域(即最后1/3场地)。
- 目标:计算某球员或某支球队在进攻三区内,所有传球的成功率(成功传球次数 / 总传球次数)。
- 数据字段假设:一个包含每脚传球信息的CSV文件。
步骤 1:模拟或读取数据
假设我们有一个名为 passes.csv 的文件,包含以下列:player_name、x(传球起点x坐标)、y(传球起点y坐标)、pass_outcome(传球结果,如 “Successful”, “Unsuccessful”, “Key Pass”)。
import pandas as pd
import numpy as np
# 为了演示,我们创建模拟数据
np.random.seed(42)
data = {
'player_name': ['Player_A'] * 50 + ['Player_B'] * 50,
'x': np.random.uniform(70, 105, 100), # 进攻三区通常在x>66(标准场地105米)
'y': np.random.uniform(0, 68, 100),
'pass_outcome': np.random.choice(['Successful', 'Unsuccessful'], 100, p=[0.7, 0.3])
}
df = pd.DataFrame(data)
print(df.head())
步骤 2:定义进攻三区并过滤数据
在标准的105m x 68m足球场中,进攻三区通常定义为 x坐标 >= 70(或根据具体数据源标准,有些定义为最后35米,即 x >= 70)。
# 定义进攻三区的阈值
ATTACKING_THIRD_X = 70 # 假设对方球门在x=105,这边是进攻方向
# 筛选出进攻三区的传球
attacking_third_passes = df[df['x'] >= ATTACKING_THIRD_X].copy()
print(f"进攻三区总传球次数: {len(attacking_third_passes)}")
步骤 3:计算传球成功率
这是核心逻辑:按球员分组,计算每个球员在进攻三区的传球成功率。
# 计算每组的总传球数和成功传球数
grouped = attacking_third_passes.groupby('player_name')['pass_outcome'].agg(
total_passes='count',
successful_passes=lambda x: (x == 'Successful').sum()
).reset_index()
# 计算成功率
grouped['success_rate'] = (grouped['successful_passes'] / grouped['total_passes']) * 100
print("\n进攻三区传球成功率统计:")
print(grouped)
输出示例:
player_name total_passes successful_passes success_rate
0 Player_A 36 26 72.222222
1 Player_B 34 24 70.588235
步骤 4:进阶分析(可选,增加实战意义)
在实际的足球分析案例中,仅仅计算“成功/总”是不够的,很多时候需要区分向前的传球或者关键传球。
1 计算“向前传球成功率”
假设数据中有 end_x(传球终点x坐标),向前传递定义为 end_x > x。
# 假设我们添加了终点坐标
df['end_x'] = df['x'] + np.random.uniform(-5, 15, 100) # 模拟终点
# 过滤进攻三区的向前传球
attacking_third_passes['is_forward'] = attacking_third_passes['end_x'] > attacking_third_passes['x']
forward_passes = attacking_third_passes[attacking_third_passes['is_forward']]
# 计算向前传球成功率 (分组计算)
forward_grouped = forward_passes.groupby('player_name')['pass_outcome'].agg(
forward_total='count',
forward_success=lambda x: (x == 'Successful').sum()
)
forward_grouped['forward_success_rate'] = (forward_grouped['forward_success'] / forward_grouped['forward_total']) * 100
print("\n进攻三区向前传球成功率:")
print(forward_grouped)
步骤 5:可视化(建议)
使用 matplotlib 或 seaborn 绘制柱状图对比。
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
plt.bar(grouped['player_name'], grouped['success_rate'], color=['skyblue', 'lightcoral'])
plt.ylabel('Pass Success Rate (%)')'Attacking Third Pass Success Rate Comparison')
plt.ylim(0, 100)
for index, value in enumerate(grouped['success_rate']):
plt.text(index, value + 1, f'{value:.1f}%', ha='center', va='bottom')
plt.show()
可能遇到的常见问题及解决(针对Python案例)
- 数据粒度问题:
- 问题:如果数据是“逐场比赛”的,需要按
match_id分组后再汇总,否则不同比赛场次权重不一。 - 解决:在
groupby中加入match_id,或者先按比赛算率,再取平均。
- 问题:如果数据是“逐场比赛”的,需要按
- 进攻三区定义不一致:
- 问题:不同数据源(如Opta、StatsBomb)对“区域”的定义不同(有的按等距1/3,有的按事件位置)。
- 解决:始终硬编码明确的x坐标阈值(如
x > 70),并在文档中注明。
- 传球结果分类:
- 问题:
pass_outcome字段可能有多种值,如 “Key Pass”、“Assist”、“Offside Pass”、“Blocked”,哪些算“不成功”? - 解决:定义清晰的规则,成功”指球到队友脚下且未被拦截/解围。
x in [‘Successful’, ‘Key Pass’, ‘Assist’]。
- 问题:
这个Python案例的核心逻辑是:
- 过滤:根据
x坐标提取进攻三区事件。 - 聚合:按
player_name分组,计数count和条件计数sum(condition)。 - 计算:
success_rate = sum(成功) / count(总) * 100。
如果你有具体的原始数据文件(比如Wyscout或StatsBomb的JSON格式),我可以帮你写更具体的解析代码。