本文目录导读:

你提到的“开源项目”具体是哪个?足球数据分析类的开源项目有不少(soccerdata、statsbombpy、FBref 爬虫、understat 相关项目等),不同项目看“半场结束前攻势”的方式不太一样。
不过一般来说,如果你想分析半场结束前(40–45+ 分钟)的攻势,思路大致如下:
通用思路
先定位时间段
把比赛事件按分钟切分,筛出:
- 上半场最后 5 分钟:
40 <= minute <= 45 - 含补时:
40 <= minute <= 45+(有的数据用45+2这种字段,需要解析)
定义“攻势”指标
常见可量化的“攻势”包括: | 指标 | 说明 | |------|------| | 射门数 | shots | | 射正数 | shots on target | | 预期进球 xG | 最能反映威胁 | | 角球 | corners | | 进攻三区触球 | touches in final third | | 对方禁区触球 | touches in penalty area | | 传球进入进攻三区 | passes into final third | | 进攻回合 | possession sequences / attacks |
按球队聚合
筛出时间段后,按 team 分组统计上述指标,就能看出哪一方在半场结束前压上。
以 StatsBomb 数据为例(statsbombpy)
from statsbombpy import sb
events = sb.events(match_id=XXXX)
# 上半场最后5分钟
late_first_half = events[
(events['minute'] >= 40) &
(events['period'] == 1)
]
# 射门
shots = late_first_half[late_first_half['type'] == 'Shot']
print(shots.groupby('team')['shot_statsbomb_xg'].agg(['count', 'sum']))
# 进攻三区传球
passes = late_first_half[
(late_first_half['type'] == 'Pass') &
(late_first_half['pass_end_location'].apply(
lambda x: isinstance(x, list) and x[0] > 80)) # x>80 约进攻三区
]
print(passes.groupby('team').size())
以 soccerdata / FBref 为例
FBref 有 "Match Events" 或 "Shot/Pass Types" 表,可以:
- 抓取事件的
Minute列; - 过滤
40 <= Minute <= 45; - 按
Squad统计 shots、xG、corners 等。
import soccerdata as sd
fbref = sd.FBref(leagues="ENG-Premier League", seasons="2023-2024")
events = fbref.read_events(match_id="...")
late = events[(events['Minute'] >= 40) & (events['Minute'] <= 45)]
late.groupby('Squad').agg({'xG': 'sum', 'Shot': 'count'})
可视化建议
- 时间轴图:横轴分钟,纵轴按球队堆叠射门/xG,突出 40–45 区间;
- 半场结束前 5 分钟 xG 对比柱状图;
- 进攻方向热图:只画 40–45 分钟的触球/传球起点。
要注意的坑
- 补时分钟:不同数据源对
45+的表示不同,有的用45,有的用46、5或单独字段; - 事件 vs 回合:单看射门会漏掉“只压上没射门”的攻势,建议结合
passes into final third或possession sequences; - 样本量:单场 5 分钟样本很小,通常要看整个赛季多场平均才有意义。