实用脚本统计头球争顶成功率如何?

wen 实用脚本 6

本文目录导读:

实用脚本统计头球争顶成功率如何?

  1. 前提与数据结构
  2. Python 脚本
  3. 脚本解释与扩展
  4. 如果数据来自 CSV 文件
  5. 进阶建议(可选增强)

统计头球争顶成功率(Aerial Duels Won Rate)是足球数据分析中非常实用的一个指标,下面我提供一个基于Python的实用脚本,它能够处理比赛事件数据并输出头球争顶的成功率。

这个脚本会覆盖数据清洗、特征计算和结果输出三个方面,你可以直接复制或根据你的数据格式进行调整。


前提与数据结构

在大多数体育数据供应商(如Opta、StatsBomb)的数据中,头球争顶通常分为两类事件:

  1. 争顶成功:球员在空中对抗中赢得球权。
  2. 争顶失败:球员在空中对抗中失去球权(或未触到球)。

假设你的数据格式为(列名):

  • player:球员姓名
  • event_type:事件类型("Aerial""Duel"
  • duel_type:对抗类型("Aerial"
  • outcome:结果("Won""Lost"
  • minute:比赛时间

Python 脚本

import pandas as pd
import numpy as np
def calculate_aerial_duel_success_rate(df):
    """
    计算头球争顶成功率(针对球员和球队)。
    参数:
        df (pd.DataFrame): 包含头球争顶事件的数据框。
    返回:
        pd.DataFrame: 包含头部争顶成功率的汇总数据。
    """
    # 1. 数据清洗与筛选
    # 只保留头球争顶事件(这里假设 duel_type == 'Aerial',或 event_type == 'Aerial')
    aerial_df = df[
        (df['event_type'] == 'Aerial') | 
        ((df['duel_type'] == 'Aerial') & (df['event_type'] == 'Duel'))
    ].copy()
    # 如果没有任何头球事件,返回空
    if aerial_df.empty:
        print("警告:数据中未找到头球争顶事件。")
        return pd.DataFrame()
    # 标准化结果列(处理大小写和不同表达方式)
    aerial_df['outcome_normalized'] = aerial_df['outcome'].str.strip().str.lower()
    aerial_df['is_won'] = np.where(aerial_df['outcome_normalized'].isin(['won', 'success', 'win', '1', 'true']), 1, 0)
    # 2. 按球员统计
    player_stats = aerial_df.groupby('player').agg(
        总争顶次数=('is_won', 'count'),
        成功次数=('is_won', 'sum')
    ).reset_index()
    player_stats['成功率(%)'] = (player_stats['成功次数'] / player_stats['总争顶次数'] * 100).round(2)
    player_stats = player_stats.sort_values('成功率(%)', ascending=False)
    # 3. 按球队统计(如果数据中有球队列)
    if 'team' in aerial_df.columns:
        team_stats = aerial_df.groupby('team').agg(
            总争顶次数=('is_won', 'count'),
            成功次数=('is_won', 'sum')
        ).reset_index()
        team_stats['成功率(%)'] = (team_stats['成功次数'] / team_stats['总争顶次数'] * 100).round(2)
        team_stats = team_stats.sort_values('成功率(%)', ascending=False)
        return player_stats, team_stats
    else:
        return player_stats
# --- 使用示例 ---
if __name__ == "__main__":
    # 模拟一份虚拟数据(实际使用中请替换为你的数据源,如CSV或API)
    data = {
        'player': ['球员A', '球员B', '球员A', '球员C', '球员B', '球员A', '球员C', '球员A', '球员B', '球员B'],
        'team': ['主队', '主队', '主队', '客队', '客队', '客队', '主队', '客队', '主队', '客队'],
        'event_type': ['Aerial', 'Duel', 'Aerial', 'Aerial', 'Aerial', 'Duel', 'Aerial', 'Aerial', 'Aerial', 'Aerial'],
        'duel_type': ['Aerial', 'Aerial', 'Aerial', 'Aerial', 'Aerial', 'Aerial', 'Aerial', 'Aerial', 'Aerial', 'Aerial'],
        'outcome': ['Won', 'Lost', 'Lost', 'Won', 'Won', 'Won', 'Lost', 'Won', 'Lost', 'Won'],  # Won=1, Lost=0
        'minute': [10, 23, 45, 67, 70, 80, 85, 88, 90, 91]
    }
    df = pd.DataFrame(data)
    print("原始数据:")
    print(df)
    print("\n")
    # 计算成功率
    result = calculate_aerial_duel_success_rate(df)
    # 输出结果
    if isinstance(result, tuple):
        player_result, team_result = result
        print("球员头球争顶成功率:")
        print(player_result)
        print("\n球队头球争顶成功率:")
        print(team_result)
    else:
        print("头球争顶成功率:")
        print(result)

脚本解释与扩展

  1. 筛选逻辑:脚本通过 event_typeduel_type 来判断是否为头球争顶,如果数据源不同,只需修改这里的条件即可。
  2. 结果标准化:现实中不同数据源对“成功”的定义可能不同(如 Won,Succ),脚本已将常见的关键词统一映射为 01
  3. 统计维度
    • 球员维度:关注个人对抗能力。
    • 球队维度(可选):关注整体高空对抗强度。
  4. 过滤条件扩展:你可以轻松增加额外参数,只统计禁区内的头球”或“只统计特定时间段”。
    • df = df[df['area'] == 'Defensive third']
  5. 百分比安全性:如果某球员争顶次数为0,round()sort_values 会自动处理,但建议在输出前检查是否为空。

如果数据来自 CSV 文件

将脚本中的模拟数据部分替换为:

df = pd.read_csv('your_match_events.csv')  # 你的CSV路径

如果数据是 JSON(如 StatsBomb):

df = pd.json_normalize(data, record_path='events')  # 根据实际结构调整

进阶建议(可选增强)

如果你想统计“特定位置”(如中后卫)或“特定时刻”(如下半场最后15分钟),可以在函数中增加参数:

def calculate_aerial_duel_success_rate(df, position_filter=None, minute_filter=None):
    # ... 在筛选后增加:
    if position_filter:
        df = df[df['position'] == position_filter]
    if minute_filter:
        df = df[df['minute'] >= minute_filter[0] & df['minute'] <= minute_filter[1]]

抱歉,评论功能暂时关闭!