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

wen 实用脚本 2

本文目录导读:

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

  1. 场景一:基于 Excel/CSV 的快速统计(最实用,无需数据库)
  2. 场景二:基于事件日志(SQL / Pandas 长表)的严谨统计
  3. 场景三:可视化热力图 + 区域命中率(进阶)
  4. 关于“成功率”口径的最终建议

要统计“高球传中争顶成功率”,首先需要定义清楚统计口径,在足球数据分析中,这个指标通常拆解为“传中成功(找到队友)”“争顶成功(队友抢到点)”

由于这属于自定义事件统计(而非标准化的Opta或StatsBomb官方格式),以下我为你提供三个不同层级的实用Python脚本(从零开始的数据整理、基于事件日志的SQL查询、以及可视化统计),你可以根据你手头的数据形式(Excel、数据库、或视频标注文本)直接复制修改。

基于 Excel/CSV 的快速统计(最实用,无需数据库)

适用情况:你有比赛录像,用Excel(Wyscout/Instat导出或自己手工记录)记录了每次传中的结果,格式为:球员、时间、传中类型(高球/低平)、落点区域、是否成功争顶、是否射门

import pandas as pd
# 1. 加载你的数据(假设列名为英文,如果是中文请对应修改)
# 列:player, time, cross_type, area, contested, won
df = pd.read_excel('crossing_data.xlsx')  # 或者 pd.read_csv('data.csv')
# 2. 数据清洗 & 筛选:只看“高球传中”(High Cross)
high_crosses = df[df['cross_type'] == 'high'].copy()  # 根据你的列名调整(如 '高球')
# 3. 定义“成功争顶”的判定标准(必须满足其一):
#    - 己方球员在对抗下(或无人对抗)触球并试图控球/射门
#    - 不包含“球出界”或“对方解围”且球权未转换的情况
# 假设你的‘won’列中 1 代表成功争顶,0 代表失败
successful_duels = high_crosses[high_crosses['won'] == 1]
total_duels = len(high_crosses)
# 4. 计算指标
success_rate = len(successful_duels) / total_duels * 100 if total_duels > 0 else 0
print(f"══════════════════════════════════════")
print(f"📊 高球传中争顶统计报告")
print(f"══════════════════════════════════════")
print(f"总高球传中次数: {total_duels}")
print(f"成功争顶(触球并控制)次数: {len(successful_duels)}")
print(f"⚠️ 争顶成功率: {success_rate:.1f}%")
print(f"══════════════════════════════════════")
# 5. 进阶:按球员拆分统计(看看谁最能抢点)
print("\n👤 按球员拆分的表现:")
player_stats = high_crosses.groupby('player').agg(
    传中总数=('time', 'count'),
    争顶成功数=('won', 'sum')
).reset_index()
player_stats['成功率'] = (player_stats['争顶成功数'] / player_stats['传中总数'] * 100).round(1)
print(player_stats.to_string(index=False))
# 6. 进阶:按落点区域统计(前点/后点/点球点)
print("\n📍 按落点区域分析(区域编码请对应你的数据):")
area_stats = high_crosses.groupby('area')['won'].agg(['sum', 'count'])
area_stats['成功率'] = (area_stats['sum'] / area_stats['count'] * 100).round(1)
print(area_stats.to_string())

基于事件日志(SQL / Pandas 长表)的严谨统计

适用情况:你手里有一份包含事件ID的长表,每条记录包含了 传中 -> 争顶 -> 结果 的串联关系。

这种数据通常有 possession_id(控球回合)或 event_id,我们需要把“传中”事件和接下来1-2秒内的“空中对抗”事件关联起来。

import pandas as pd
# 假设数据结构如下:
# events = ['type': 'Cross' or 'Aerial_Duel', 'time': 秒, 'player_id': ..., 'outcome': 'complete'/'incomplete']
# 数据加载示例(简化版)
data = {
    'event_id': [1,2,3,4],
    'type': ['Cross', 'Aerial_Duel', 'Cross', 'Aerial_Duel'],
    'time': [10.0, 10.8, 25.0, 25.7],  # 传中后0.8秒发生对抗
    'possession_team': ['TeamA', 'TeamA', 'TeamB', 'TeamB'],
    'result': ['complete', 'success', 'incomplete', 'fail']
}
df = pd.DataFrame(data)
# 统计核心逻辑:计算每一次传中后,是否在2秒内产生了“成功”的空中对抗
df['next_duel'] = df.groupby('possession_team')['time'].shift(-1)  # 找下一个事件
df['duel_gap'] = df['next_duel'] - df['time']
# 筛选:传中事件
crosses = df[df['type'] == 'Cross'].copy()
duels = df[df['type'] == 'Aerial_Duel'].copy()
# 合并(简化方案:通过时间差关联)
# 更严谨的做法是通过球权ID串联,这里用merge_asof时间近似匹配
merged = pd.merge_asof(crosses, duels, 
                       left_on='time', right_on='time',
                       by='possession_team',  # 同一队
                       direction='forward',
                       tolerance=1.5)  # 传中后1.5秒内的对抗
# 计算成功率
attempts = len(merged)
successful = (merged['result_y'] == 'success').sum()  # result_y是duel的结果
print(f"传中争顶成功率: {successful/attempts*100:.1f}%")

可视化热力图 + 区域命中率(进阶)

如果你想用Python绘制一张足球场平面图,把每次传中落点标出来,并给“成功争顶”的点标绿色,“失败”标红色,这个脚本底层逻辑是一样的,只是在统计后加上 matplotlib 绘图:

import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.patches import Rectangle, Arc
# 假设你已有 df(包含 x_coord, y_coord, won 列)
def plot_pitch_and_success(df):
    fig, ax = plt.subplots(figsize=(10, 7))
    # 绘制球场简化轮廓
    ax.add_patch(Rectangle((0, 0), 105, 68, fill=False))
    ax.add_patch(Arc((52.5, 34), 40, 40, theta1=0, theta2=180, color='black'))
    # 绘制争顶点
    success_pts = df[df['won'] == 1]
    fail_pts = df[df['won'] == 0]
    ax.scatter(success_pts['x'], success_pts['y'], c='green', label=f'成功 ({len(success_pts)}次)', s=50)
    ax.scatter(fail_pts['x'], fail_pts['y'], c='red', label=f'失败 ({len(fail_pts)}次)', s=50)
    # 计算整体成功率
    rate = len(success_pts) / (len(success_pts) + len(fail_pts)) * 100
    ax.set_title(f'高球传中争顶次数分布\n整体成功率: {rate:.1f}%')
    ax.legend()
    plt.show()
# 调用
# plot_pitch_and_success(your_data_with_coordinates)

成功率”口径的最终建议

由于“争顶”在官方统计中往往和“对抗成功”绑定,在你自己写脚本时,建议采用以下中国足球分析师常用口径

  1. 分母:本方在对方半场(或进攻三区)的高球传中(包括角球和运动战传中)。
  2. 分子:传中后,本方球员主动起跳触球,且球权仍然在本方(无论是直接攻门、回做还是二点球)。
  3. 不计数的情况:门将出击将球击出、球直接出底线、还没争顶就被吹犯规。

希望这些脚本能直接帮到你,如果你的数据格式比较特殊(比如视频标注只有文本),欢迎把表格的前几行数据截图发来,我帮你定制代码。

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