本文目录导读:

统计头球争顶成功率是足球数据分析中的一项实用技能,无论是用于赛后复盘、球探报告还是游戏(如FM)中的球员评估,都非常有价值。
这里提供一个使用Python编写的实用脚本框架,以及一个使用Excel操作的思路,方便不同技术背景的你使用。
Python 脚本(推荐,最灵活)
这个脚本假设你已经有一份结构化的比赛数据(例如从 Opta、StatsBomb 或手动录制的CSV文件)。
数据格式假设:
你的CSV文件(headers.csv)需要包含以下几列(至少):
| player | team | minute | outcome | distance |
|---|---|---|---|---|
| 张三 | 红队 | 23 | 成功 | 12 |
| 李四 | 蓝队 | 45 | 失败 | 8 |
| 王五 | 红队 | 67 | 成功 | 15 |
player:球员名team:球队名minute:比赛时间outcome:结果(“成功”或“失败”)distance:争顶距离(可选,用于进阶统计)
脚本代码:
import pandas as pd
def calculate_heading_stats(file_path):
"""
计算头球争顶成功率的基本统计。
Args:
file_path (str): CSV文件的路径。
"""
try:
# 读取数据
df = pd.read_csv(file_path)
# 数据清洗:确保 outcome 列是标准化的
df['outcome'] = df['outcome'].str.strip().str.lower()
df['outcome'] = df['outcome'].replace({'succeed': '成功', 'successful': '成功', 'win': '成功',
'fail': '失败', 'failed': '失败', 'lose': '失败', 'lost': '失败'})
# 只保留有效数据
df = df[df['outcome'].isin(['成功', '失败'])]
# --- 核心统计 ---
# 1. 总体成功率
total_attempts = len(df)
total_success = (df['outcome'] == '成功').sum()
overall_success_rate = (total_success / total_attempts * 100) if total_attempts > 0 else 0
# 2. 球员分组统计(重点)
print("=" * 50)
print("头球争顶统计报告")
print("=" * 50)
print(f"总争顶次数: {total_attempts}")
print(f"总体成功率: {overall_success_rate:.2f}%")
print("\n--- 球员统计明细 ---")
player_stats = df.groupby('player').agg(
球队=('team', 'first'), # 取该球员的第一支队伍(假设不转会)
总争顶次数=('outcome', 'count'),
成功次数=('outcome', lambda x: (x == '成功').sum())
).reset_index()
player_stats['成功率'] = (player_stats['成功次数'] / player_stats['总争顶次数'] * 100).round(2)
player_stats = player_stats.sort_values('成功率', ascending=False) # 按成功率排序
# 打印表格(也可以直接输出到CSV)
print(player_stats.to_string(index=False))
# 3. 团队统计(可选)
print("\n--- 团队统计 ---")
team_stats = df.groupby('team').agg(
总争顶次数=('outcome', 'count'),
成功次数=('outcome', lambda x: (x == '成功').sum())
).reset_index()
team_stats['成功率'] = (team_stats['成功次数'] / team_stats['总争顶次数'] * 100).round(2)
team_stats = team_stats.sort_values('成功率', ascending=False)
print(team_stats.to_string(index=False))
return player_stats # 返回给其他程序使用
except FileNotFoundError:
print(f"错误:找不到文件 {file_path}")
except KeyError as e:
print(f"错误:缺少必要的列 - {e},请确保CSV包含 'player', 'team', 'outcome' 列。")
# --- 使用示例 ---
if __name__ == "__main__":
# 假设你的数据文件名为 'match_headers.csv'
stats = calculate_heading_stats('match_headers.csv')
Excel/Google Sheets 公式(无需编程)
如果你只有手动记录的数据,或者不想用Python,Excel是最快的方法。
数据准备:
在表格中新建三列:球员,队伍,结果(填“成功”或“失败”)。
使用 COUNTIFS 函数:
在任意空白单元格输入以下公式:
计算某球员(例如张飞)的争顶总数:
=COUNTIFS(A:A, "张飞", C:C, "成功") + COUNTIFS(A:A, "张飞", C:C, "失败")
计算成功率(综合上面两个条件):
=COUNTIFS(A:A, "张飞", C:C, "成功") / (COUNTIFS(A:A, "张飞", C:C, "成功") + COUNTIFS(A:A, "张飞", C:C, "失败"))
将此单元格格式设置为“百分比”。
进阶:成功率”的权重问题
为了让统计更有实际意义,你可以考虑以下调整(脚本中也可以加入权重):
- 阵地战 vs 定位球:定位球(角球、任意球)中有更高比例的出手,建议分开关联。
- 可以增加一列
场景,分别统计不同场景下的成功率。
- 可以增加一列
- 防守端 vs 进攻端:防守端的头球解围成功率高,但没太多价值;进攻端的头球攻门,只要顶到门框内就算“成功”,衡量标准不同。
- 建议增加一列
类型(如:攻门/解围/摆渡),分别统计才更有意义。
- 建议增加一列
- 对抗强度:如果数据源允许,可以引入“在无人防守下”和“在对抗下”的标签。
在Python脚本中,df.groupby(['player', '场景']) 即可轻松实现多维度的透视表。
总结与建议
- 对于普通球迷/新手:推荐使用 Excel 的透视表 功能,选择“球员”为行,“结果”为值,计算“成功”的数量,然后除以总数。
- 对于数据分析师/资深球迷:建议使用上面的 Python 脚本,因为它可以处理大量数据,并且能方便地结合距离、场景、比赛重要性等多维度因素。
如果你希望脚本能自动从视频或实时传入的数据中识别头球,那需要复杂得多的模型,而这主要取决于你手头数据的结构化程度——大多数情况下,先手动整理成表格,再交给脚本处理是最实用的路径。