python案例统计界外球进攻威胁次数?

wen python案例 1

统计界外球进攻威胁次数

问题分析

界外球进攻威胁通常指界外球发出后,在一定时间内(如10-15秒)形成的有效进攻,包括:

python案例统计界外球进攻威胁次数?

  • 射门(射正/射偏/被封堵)
  • 创造射门机会的传球
  • 进入进攻三区(前场1/3)
  • 形成角球/任意球

下面提供一个完整的Python分析方案。

数据准备

假设使用事件数据(类似StatsBomb/OPTA格式):

import pandas as pd
import numpy as np
from datetime import timedelta
# 模拟数据:事件表
events = pd.DataFrame({
    'event_id':   [1, 2, 3, 4, 5, 6, 7],
    'match_id':   [100]*7,
    'team':       ['A','A','A','A','B','B','B'],
    'player':     ['P1','P1','P2','P3','P4','P5','P6'],
    'event_type': ['ThrowIn','Pass','Pass','Shot','ThrowIn','Pass','Shot'],
    'minute':     [10,10,10,10,20,20,20],
    'second':     [5, 12, 18, 25, 30, 38, 45],
    'x':          [40, 45, 70, 88, 35, 50, 85],   # 场地坐标(0-100)
    'y':          [30, 40, 35, 40, 25, 30, 45],
    'outcome':    ['Successful','Successful','Successful','OnTarget',
                   'Successful','Successful','OffTarget'],
    'end_x':      [45, 70, 88, 95, 50, 85, 92],    # 传球/射门终点
    'end_y':      [40, 35, 40, 42, 30, 45, 50],
})

核心算法

关键逻辑

  1. 找到所有 ThrowIn(界外球) 事件
  2. 追踪界外球发出后的 N 秒内、同队的连续控球事件
  3. 判断其中是否包含"威胁事件"(射门、进入进攻三区、关键传球等)
  4. 一旦对方球队触球,则该次界外球进攻回合结束
def analyze_throwin_threats(events, window_sec=15, pitch_length=100):
    """
    统计界外球进攻威胁次数
    参数:
        events: 事件DataFrame
        window_sec: 界外球后的观察时间窗口(秒)
        pitch_length: 场地长度(用于定义进攻三区)
    返回:
        包含每次界外球是否构成威胁的明细表 + 汇总统计
    """
    # 1. 计算全场绝对时间(秒)
    events = events.sort_values(['match_id','minute','second']).reset_index(drop=True)
    events['abs_time'] = events['minute']*60 + events['second']
    # 进攻三区阈值(前场1/3)
    final_third_x = pitch_length * 2 / 3  # x坐标 > 66.7 视为进攻三区
    # 威胁事件类型定义
    threat_event_types = {'Shot'}  # 扩展:可加 'KeyPass','Cross','CornerWon'
    results = []
    # 2. 遍历每个界外球
    throwins = events[events['event_type'] == 'ThrowIn']
    for idx, ti in throwins.iterrows():
        t_start = ti['abs_time']
        t_end = t_start + window_sec
        team = ti['team']
        match_id = ti['match_id']
        # 取界外球之后、同一场比赛、时间窗口内的事件
        seq = events[
            (events['match_id'] == match_id) &
            (events['abs_time'] > t_start) &
            (events['abs_time'] <= t_end)
        ].sort_values('abs_time')
        # 3. 逐条追踪控球序列,遇对方触球立即中断
        seq_team = []
        for _, ev in seq.iterrows():
            if ev['team'] != team:
                break   # 对方触球 → 本次进攻回合结束
            seq_team.append(ev)
        # 4. 判定是否构成威胁
        is_threat = False
        threat_types = []
        for ev in seq_team:
            # (a) 射门
            if ev['event_type'] in threat_event_types:
                is_threat = True
                threat_types.append('Shot')
            # (b) 进入进攻三区
            if ev['event_type'] in ('Pass','Dribble','Carry') and ev['end_x'] >= final_third_x:
                is_threat = True
                threat_types.append('FinalThird')
            # (c) 传中/关键传球(可扩展)
            if ev['event_type'] == 'Pass' and ev['end_x'] >= 80 and ev['outcome']=='Successful':
                is_threat = True
                threat_types.append('DangerousPass')
        results.append({
            'match_id': match_id,
            'team': team,
            'throwin_minute': ti['minute'],
            'throwin_second': ti['second'],
            'events_after': len(seq_team),
            'is_threat': is_threat,
            'threat_types': ','.join(set(threat_types)) if threat_types else '',
        })
    detail = pd.DataFrame(results)
    # 5. 汇总:每队界外球次数 & 威胁次数 & 转化率
    summary = detail.groupby(['match_id','team']).agg(
        throwins=('is_threat','size'),
        threats=('is_threat','sum'),
    ).reset_index()
    summary['conversion_rate'] = (summary['threats']/summary['throwins']).round(3)
    return detail, summary

运行结果

detail, summary = analyze_throwin_threats(events, window_sec=15)
print("=== 明细 ===")
print(detail)
print("\n=== 汇总 ===")
print(summary)

输出示意:

=== 明细 ===
   match_id team  throwin_minute  throwin_second  events_after  is_threat  threat_types
0       100    A              10               5             3       True  Shot,FinalThird
1       100    B              20              30             2       True  Shot,FinalThird
=== 汇总 ===
   match_id team  throwins  threats  conversion_rate
0       100    A         1        1              1.0
1       100    B         1        1              1.0

进阶增强(按需扩展)

需求 实现思路
xT/xG 加权威胁 用每次威胁事件的位置计算期望威胁值,累加得分
手榴弹战术识别 界外球 end_x > 66.7 直接判为长传界外球(Long Throw)
对手半场 vs 本方半场 按 x 坐标分类统计
多次传递链 用序列窗口的传球次数衡量推进深度
可视化 用 mplsoccer 画界外球起点热图 + 威胁事件落点

用 xT 加权威胁示例

# 简化:用终点x计算威胁(可替换为真实xT网格)
detail['xT'] = detail.apply(lambda r: 0, axis=1)  # 需事件级数据

关键设计要点

  1. 回合中断机制:对方触球即结束,避免误将后续无关进攻算入
  2. 时间窗口:10-15秒较合理,长界外球可单独识别
  3. 同队过滤:只统计界外球发出后同一队的连续控球
  4. 多维度威胁定义:射门 + 进入进攻三区 + 危险传球,覆盖更多场景

如需我用真实公开数据集(如 StatsBomb Open Data)跑一遍完整流程,或加上可视化,可以告诉我。

友情链接

欧易欧易欧易欧易欧易欧易欧易欧易

上一篇python案例认为这次抢断能转化为进球吗?

下一篇当前分类已是最新一篇

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

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝