实用脚本统计高球传中争顶成功率?

wen 实用脚本 5

本文目录导读:

实用脚本统计高球传中争顶成功率?

  1. 方案一:基于Python(适用于进阶数据分析)
  2. 方案二:轻量级Excel/CSV模板(适合手动记录)
  3. 核心定义说明
  4. 如何适配你的数据?

要统计高球传中(通常指传中球)的争顶成功率,首先需要定义清楚统计口径,在足球数据统计中,通常分为“传中到位率”(传中是否找到队友)和“争顶成功率”(队友是否在争顶中胜出并完成有效控制)。

下面我提供一个基于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,"张三")

核心定义说明

在脚本中,“争顶成功”默认定义为:

  1. 头球射门命中门框范围;
  2. 头球摆渡给队友形成有效控球;
  3. 防守方解围不算成功(若统计进攻方)。

如果你想调整规则(顶偏也算争顶成功”),只需在calculate_headers_success_ratesuccess判断条件中修改即可(例如改成outcome == 'success' or outcome == 'blocked')。


如何适配你的数据?

你只需要告诉我:

  1. 你的数据源是什么格式?(CSV/Excel/JSON?)
  2. 有哪些关键字段?(比如是否有坐标、球员名、结果标签?)
  3. “成功”你的定义是什么?

我可以为你定制专属的脚本函数,如果你有样例数据(哪怕几行),发给我,我可以直接写出匹配你格式的代码。

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