本文目录导读:

要统计高球传中(通常指传中球)的争顶成功率,首先需要定义清楚统计口径,在足球数据统计中,通常分为“传中到位率”(传中是否找到队友)和“争顶成功率”(队友是否在争顶中胜出并完成有效控制)。
下面我提供一个基于Python的实用分析脚本模板,它包含数据预处理、核心指标计算和可视化三个部分,你可以根据自己的数据源(如StatsBomb、Wyscout或手动记录)进行调整。
基于Python(适用于进阶数据分析)
如果你有详细的球员事件数据(包含坐标和结果标签),用这个脚本最准确。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# =============================================
# 第一步:定义数据结构和清洗
# =============================================
# 假设你的CSV数据包含以下列:
# - match_id: 比赛ID
# - player_name: 执行传中的球员
# - receiver_name: 争抢头球的球员
# - event_type: 'cross' (传中) / 'aerial_duel' (争顶)
# - outcome: 'success' (成功) / 'fail' (失败) / 'blocked' (被封堵)
# - x, y: 事件发生的坐标(0-100为宜)
def load_and_clean_data(filepath):
"""加载数据并标准化列名"""
df = pd.read_csv(filepath)
# 标准列名映射(若无此列则跳过)
required_cols = ['match_id', 'player_name', 'receiver_name',
'event_type', 'outcome', 'x', 'y']
for col in required_cols:
if col not in df.columns:
# 如果缺列,手动填充默认值以便运行
if col == 'outcome':
df[col] = 'success' # 默认全部为成功(示例)
elif col == 'receiver_name':
df[col] = 'unknown'
elif col == 'x':
df[col] = 50 # 默认中路
elif col == 'y':
df[col] = 50
# 只保留传中和争顶事件
df = df[df['event_type'].isin(['cross', 'aerial_duel'])]
# 将传中事件与随后的争顶事件关联(假设争顶紧跟着传中)
# 这里简化为:传中后的下一个事件视为争顶结果
df['next_outcome'] = df['outcome'].shift(-1)
df['next_player'] = df['receiver_name'].shift(-1)
return df
# =============================================
# 第二步:核心统计函数
# =============================================
def calculate_headers_success_rate(df):
"""
计算争顶成功率
定义:成功 = 队友在该次传中后完成头球射门、头球摆渡或控球权在队友脚下
返回字典,包含整体、分球员、分区域的成功率
"""
# 筛选出有效传中(有争顶跟随的)
crosses = df[df['event_type'] == 'cross'].copy()
# 计算总体成功率
overall_success = crosses['next_outcome'].value_counts()
total_crosses = len(crosses)
success_count = overall_success.get('success', 0)
# --- 按球员统计 ---
player_stats = crosses.groupby('player_name').apply(
lambda x: pd.Series({
'total_crosses': len(x),
'successes': (x['next_outcome'] == 'success').sum(),
'success_rate': round((x['next_outcome'] == 'success').mean() * 100, 1)
})
).reset_index()
# --- 按区域统计(基于传中坐标x)---
# 假设x坐标:<30为深传,30-70中路,>70底线
def categorize_zone(x_val):
if x_val < 30:
return 'Deep'
elif x_val <= 70:
return 'Middle'
else:
return 'Byline'
crosses['zone'] = crosses['x'].apply(categorize_zone)
zone_stats = crosses.groupby('zone')['next_outcome'].apply(
lambda x: round((x == 'success').mean() * 100, 1)
).reset_index()
zone_stats.columns = ['Zone', 'Success_Rate']
# --- 按接收者统计(争顶者)---
receiver_stats = crosses.groupby('receiver_name').apply(
lambda x: pd.Series({
'attempts': len(x),
'successes': (x['next_outcome'] == 'success').sum(),
'rate': round((x['next_outcome'] == 'success').mean() * 100, 1)
})
).reset_index()
return {
'overall_rate': round(success_count / total_crosses * 100, 1),
'player_stats': player_stats.sort_values('success_rate', ascending=False),
'zone_stats': zone_stats,
'receiver_stats': receiver_stats.sort_values('rate', ascending=False)
}
# =============================================
# 第三步:可视化输出
# =============================================
def plot_results(results):
"""柱状图展示各球员成功率"""
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 1. 球员传中成功率
top_players = results['player_stats'].head(10)
axes[0].barh(top_players['player_name'], top_players['success_rate'],
color='skyblue')
axes[0].set_title('Top 10 Players - Cross Header Success Rate')
axes[0].set_xlabel('Success Rate (%)')
# 2. 分区成功率
axes[1].bar(results['zone_stats']['Zone'],
results['zone_stats']['Success_Rate'], color='lightgreen')
axes[1].set_title('Success Rate by Crossing Zone')
axes[1].set_ylim(0, 100)
# 3. 最有效率的头球手
top_headers = results['receiver_stats'].head(5)
axes[2].barh(top_headers['receiver_name'], top_headers['rate'],
color='salmon')
axes[2].set_title('Top 5 Headers')
axes[2].set_xlabel('Success Rate (%)')
plt.tight_layout()
plt.show()
# =============================================
# 执行示例
# =============================================
if __name__ == "__main__":
# 模拟数据(实际应用请替换为真实文件路径)
sample_data = pd.DataFrame({
'match_id': [1,1,1,1,1,1,1,1],
'player_name': ['A','B','A','C','A','B','A','C'],
'receiver_name': ['X','Y','X','Z','X','Y','X','Z'],
'event_type': ['cross','cross','cross','cross','cross','cross','cross','cross'],
'outcome': ['success','fail','success','success','fail','fail','success','success'],
'x': [25, 45, 75, 60, 20, 80, 50, 30],
'y': [60, 40, 55, 50, 65, 70, 45, 35]
})
# 保存临时CSV
sample_data.to_csv('sample_crosses.csv', index=False)
# 运行分析
df = load_and_clean_data('sample_crosses.csv')
results = calculate_headers_success_rate(df)
print(f"整体争顶成功率: {results['overall_rate']}%")
print("\n球员统计详情:")
print(results['player_stats'])
plot_results(results)
轻量级Excel/CSV模板(适合手动记录)
如果你没有专业数据,可以用这个Excel公式逻辑,然后配合Python读取:
Excel列结构: | 时间 | 传中球员 | 落点区域 | 争顶队友 | 争顶结果 | |------|----------------|---------|---------|---------| | 1:23 | 张三 | 前点 | 李四 | 成功/失败 |
核心公式(在Excel中):
=COUNTIFS(E:E,"成功", B:B,"张三") / COUNTIF(B:B,"张三")
核心定义说明
在脚本中,“争顶成功”默认定义为:
- 头球射门命中门框范围;
- 头球摆渡给队友形成有效控球;
- 防守方解围不算成功(若统计进攻方)。
如果你想调整规则(顶偏也算争顶成功”),只需在calculate_headers_success_rate的success判断条件中修改即可(例如改成outcome == 'success' or outcome == 'blocked')。
如何适配你的数据?
你只需要告诉我:
- 你的数据源是什么格式?(CSV/Excel/JSON?)
- 有哪些关键字段?(比如是否有坐标、球员名、结果标签?)
- “成功”你的定义是什么?
我可以为你定制专属的脚本函数,如果你有样例数据(哪怕几行),发给我,我可以直接写出匹配你格式的代码。