这个实用脚本显示低平球传中次数?

wen 实用脚本 3

本文目录导读:

这个实用脚本显示低平球传中次数?

  1. 方案一:处理 Wyscout / StatsBomb 事件数据(JSON 格式)
  2. 方案二:极简通用版(手动录入比赛事件,适用于任何数据)
  3. 如何选择?
  4. 重点提醒(数据字段问题)

要制作一个显示低平球传中次数的实用脚本,我需要先确认您使用的数据源(如 StatsBomb、Wyscout、Opta 或普通的比赛 CSV 数据),因为“低平球”在不同数据源中的字段定义不同。

我可以先给您一个通用且最常用的 Python 脚本框架(适用于 Wyscout 或 StatsBomb 格式),并提供一个基于现场观感(通过视频时间戳或手动输入)的极简脚本。

由于没有具体数据文件,我假设您使用的是Wyscout 事件数据(这是目前最流行的免费公开数据集格式),其中传球类型用 tags 表示,高度用 104(低平球)标识。

以下是两个实用脚本,您可以根据您手里的数据形态选择:


处理 Wyscout / StatsBomb 事件数据(JSON 格式)

此脚本会统计指定球队(或全部球队)在比赛中低平球传中的具体次数,并打印出每一次的详细位置。

import json
from collections import Counter
# ------------------ 配置区 ------------------
# 请将您的数据文件放在同目录下,并修改文件名
EVENT_FILE = "events.json"  
# 球队名称(如果只想统计某队,填 None 则统计所有球队)
TARGET_TEAM = None  # "Liverpool" 或 "FC Barcelona"
# 传中事件子类型(Wyscout 中传中是 8,Open Play 是 1)
CROSS_SUBTYPE = 8  
# ------------------ 核心代码 ------------------
def load_events(path):
    with open(path, 'r', encoding='utf-8') as f:
        return json.load(f)
def is_low_cross(event):
    """
    判断是否为低平球传中:
    1. 必须是传中 (subtype 或 eventName 为 Cross)
    2. 传球高度 tag 必须为 104 (Low)
    """
    # ---- 处理 Wyscout 格式 ----
    if 'subEventId' in event:
        if event['subEventId'] != CROSS_SUBTYPE:
            return False
        # 检查 tags 是否包含精准/低平球 (id=104)
        tags = [tag['id'] for tag in event.get('tags', [])]
        # 104 在 Wyscout 中代表 "Low" (贴地飞行)
        return 104 in tags
    # ---- 处理 StatsBomb 格式 ----
    if event.get('type', {}).get('name') == 'Pass':
        if event.get('pass', {}).get('height', {}).get('name') == 'Ground Pass':
            pass_type = event.get('pass', {}).get('type', {}).get('name')
            if pass_type == 'Cross':
                return True
    return False
def main():
    events = load_events(EVENT_FILE)
    # 提取比赛 ID (如果有)
    match_ids = set(e.get('matchId', 'Unknown') for e in events)
    low_crosses = []
    for ev in events:
        # 过滤球队
        team_name = ev.get('team', {}).get('name', 'Unknown')
        if TARGET_TEAM and team_name != TARGET_TEAM:
            continue
        if is_low_cross(ev):
            # 提取关键信息
            info = {
                'match': ev.get('matchId', 'N/A'),
                'team': team_name,
                'player': ev.get('player', {}).get('name', 'Unknown'),
                'minute': ev.get('minute', 0) + ev.get('second', 0)/60,
                'x': ev.get('positions', [{}])[0].get('x', 0) if ev.get('positions') else None,
                'y': ev.get('positions', [{}])[0].get('y', 0) if ev.get('positions') else None,
                'outcome': 'Successful' if 1801 in [t['id'] for t in ev.get('tags', [])] else 'Unsuccessful'
            }
            low_crosses.append(info)
    # ----- 输出结果 -----
    print(f"\n📊 数据统计:共发现 {len(low_crosses)} 次低平球传中\n")
    print("-" * 60)
    for i, cross in enumerate(low_crosses, 1):
        print(f"{i:2d}. 第{cross['minute']:.0f}分钟 | {cross['team']} | "
              f"{cross['player']} | 位置({cross['x']}, {cross['y']}) | {cross['outcome']}")
    # 按队伍统计
    print("\n📈 球队低平球传中次数:")
    team_counts = Counter(c['team'] for c in low_crosses)
    for team, count in team_counts.most_common():
        print(f"   {team}: {count} 次")
if __name__ == "__main__":
    main()

极简通用版(手动录入比赛事件,适用于任何数据)

如果您没有现成的 JSON 数据文件,或者您是在看视频录像时手动记录,可以用这个交互式脚本,每次按回车记录一次,自动计数:

import sys
def run_tracker():
    """交互式低平球传中计数器(适合边看比赛边按)"""
    print("⚽ 低平球传中计数器")
    print("按 [Y] 记录一次,按 [C] 查看统计,按 [Ctrl+C] 退出\n")
    count = 0
    details = []
    while True:
        try:
            cmd = input(">>> ").strip().lower()
            if cmd == 'y':
                count += 1
                minute = input("   分钟数(如45.3): ")
                details.append(f"   {len(details)+1:2d}. 第{minute}分钟")
                print(f"   ✅ 已记录!当前总数: {count}")
            elif cmd == 'c':
                print(f"\n📊 总计: {count} 次")
                for d in details:
                    print(d)
                print()
        except KeyboardInterrupt:
            print(f"\n\n最终结果:共 {count} 次低平球传中")
            break
if __name__ == "__main__":
    run_tracker()

如何选择?

场景 推荐方案
已有 Wyscout 或 StatsBomb 的 JSON 事件文件 方案一
只有 普通 CSV 表格(列如 Time, Event, Height) 把方案一稍作修改,将 JSON 解析改为 csv.DictReader(可留言我帮您改)
纯人工观赛,没有数据文件 方案二

重点提醒(数据字段问题)

  • Wyscout:低平球标签 104,传中事件 ID 为 8
  • StatsBombheight=Ground Passpass.type=Cross
  • 如果您手里的数据是 Opta 格式,字段名通常会叫 Pass.Height(值包含 Ground)和 Pass.Type(值包含 Cross),请告诉我具体字段名,我可以立刻调整。

如果有具体的数据文件样例(前几行),您可以直接贴到评论区,我帮您把脚本改到完全匹配、直接可跑!

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