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

wen 实用脚本 6

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

下面给你一套可落地的脚本方案,用于统计足球比赛中"高球传中后争顶成功"的成功率,分为数据格式定义 → 核心算法 → 完整脚本 → 使用说明。

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


统计口径定义(关键!)

先明确指标,否则脚本没意义:

概念 定义
高球传中 (High Cross) 传中球的落点高度 > 2m,或明确标注为 high/lob cross
争顶事件 (Aerial Duel) 传中落点 3 秒内发生的头球/胸部以上争抢
争顶成功 争顶后球权归属进攻方,或形成射门/二次进攻
成功率 争顶成功次数 ÷ 争顶总次数 × 100%

数据输入格式(CSV / DataFrame)

建议事件数据如下(可按你现有数据源调整列名):

match_id,event_id,team,event_type,minute,second,x,y,target_x,target_y,cross_height,duel_winner,duel_outcome
M001,1001,Home,cross,23,15,80,30,20,15,high,Away,loose
M001,1002,Home,cross,45,02,75,25,18,12,high,Home,retained
M001,1003,Away,cross,67,40,20,70,82,78,high,Home,cleared
M001,1004,Home,cross,88,10,70,28,15,10,low,Home,retained

字段说明:

  • cross_height: high / low
  • duel_winner: 争顶获胜球队
  • duel_outcome: retained(进攻方控球)/ cleared(解围)/ loose(球权不明)

完整 Python 脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
高球传中争顶成功率统计脚本
用法: python cross_aerial_stats.py events.csv
"""
import sys
import pandas as pd
def load_data(path: str) -> pd.DataFrame:
    df = pd.read_csv(path)
    required = {"match_id", "team", "event_type", "cross_height",
                "duel_winner", "duel_outcome"}
    missing = required - set(df.columns)
    if missing:
        raise ValueError(f"缺少必要列: {missing}")
    return df
def filter_high_crosses(df: pd.DataFrame) -> pd.DataFrame:
    """只保留高球传中 + 存在争顶记录的事件"""
    mask = (
        df["event_type"].str.lower().eq("cross")
        & df["cross_height"].str.lower().eq("high")
        & df["duel_winner"].notna()
    )
    return df[mask].copy()
def is_success(row) -> bool:
    """争顶成功判定:获胜方 == 传球方 且 结果为 retained"""
    return (
        str(row["duel_winner"]).strip() == str(row["team"]).strip()
        and str(row["duel_outcome"]).strip().lower() == "retained"
    )
def compute_stats(df: pd.DataFrame) -> pd.DataFrame:
    df = df.copy()
    df["success"] = df.apply(is_success, axis=1)
    # 按球队统计(进攻方视角)
    grp = df.groupby(["match_id", "team"]).agg(
        crosses=("event_id", "count") if "event_id" in df.columns else ("team", "count"),
        wins=("success", "sum"),
    ).reset_index()
    grp["success_rate"] = (grp["wins"] / grp["crosses"] * 100).round(2)
    # 汇总总计
    total = pd.DataFrame([{
        "match_id": "TOTAL",
        "team": "ALL",
        "crosses": grp["crosses"].sum(),
        "wins": grp["wins"].sum(),
        "success_rate": round(grp["wins"].sum() / grp["crosses"].sum() * 100, 2)
        if grp["crosses"].sum() else 0.0,
    }])
    return pd.concat([grp, total], ignore_index=True)
def main():
    if len(sys.argv) < 2:
        print("用法: python cross_aerial_stats.py events.csv")
        sys.exit(1)
    path = sys.argv[1]
    df = load_data(path)
    high = filter_high_crosses(df)
    if high.empty:
        print("⚠️ 没有符合条件的高球传中记录")
        sys.exit(0)
    stats = compute_stats(high)
    print("\n==== 高球传中争顶成功率 ====\n")
    print(stats.to_string(index=False))
    # 可选:导出
    out = path.replace(".csv", "_aerial_stats.csv")
    stats.to_csv(out, index=False, encoding="utf-8-sig")
    print(f"\n已导出: {out}")
if __name__ == "__main__":
    main()

运行与输出示例

$ python cross_aerial_stats.py events.csv
==== 高球传中争顶成功率 ====
match_id   team  crosses  wins  success_rate
    M001   Away        2     0          0.00
    M001   Home        2     1         50.00
   TOTAL    ALL        4     1         25.00
已导出: events_aerial_stats.csv

可扩展方向

  1. 分区域统计:按 target_y 分左/中/右三区,看哪侧传中争顶效率高。
  2. 分时段统计:按 15 分钟区间,观察体能下降对争顶成功率影响。
  3. 二次进攻转化:结合 next_event 字段,统计争顶成功后 10 秒内是否形成射门。
  4. 可视化:用 matplotlib/plotly 出柱状图或热力图。
  5. 对接数据源:可替换为 StatsBomb / Opta / Wyscout 的事件导出(改列名映射即可)。

常见坑位提醒

  • 数据源不同事件模型不同:Opta 的 Aerial 和 StatsBomb 的 Duel 结构差异大,需先做字段映射。
  • "争顶成功"口径要统一:是"赢下球权"还是"形成射门",两种口径成功率差异可达 20%+。
  • 传中方向:需过滤掉角球/任意球直接传中(若只统计运动战),可用 event_type 或 set-piece 标记筛掉。

需要我按你实际的数据格式(StatsBomb JSON / Opta feeds)定制解析部分吗?把样例数据贴一下我可以直接改成能跑的版本。

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