如何分析半场结束前攻势 —— Python 案例思路
你问的"怎么看半场结束前攻势",通常指足球赛事数据分析场景,下面给你一套完整的分析框架和 Python 代码示例。

分析思路(核心逻辑)
半场结束前(通常指 40-45分钟 或 43-45+补时)的攻势判断,需要综合以下几个维度:
| 维度 | 指标 | 说明 |
|---|---|---|
| 时间窗口 | 40'-45+' | 定义"半场结束前"区间 |
| 射门 | 射门数、射正数、xG | 攻势强度 |
| 控球 | 控球率变化、进攻三区传球 | 压制程度 |
| 角球/定位球 | 角球数、前场任意球 | 施压信号 |
| 危险进攻 | dangerous attacks | 部分数据源提供 |
| 趋势对比 | 与前35分钟对比 | 是否"加强" |
Python 实现示例
数据准备(假设用 football-data 或自采数据)
import pandas as pd
import numpy as np
# 示例:事件级数据(每条记录是一次进攻事件)
# 实际可从 StatsBomb / FBref / 懂球帝API 获取
data = pd.DataFrame({
'match_id': [1]*20,
'team': ['A','A','B','A','B','A','A','B','A','A',
'B','A','A','B','A','A','B','A','A','B'],
'minute': [5,12,18,22,28,33,38,40,41,43,
44,44,45,45,45,46,46,47,48,49], # 含补时
'event_type': ['shot','pass','corner','shot','shot','pass','shot','pass',
'shot','corner','shot','shot','shot','pass','corner',
'shot','pass','shot','shot','corner'],
'xg': [0.05,0,0.02,0.08,0.05,0,0.12,0,0.15,0.02,
0.10,0.20,0.18,0,0.03,0.25,0,0.30,0.22,0.05],
'pitch_zone': ['att3','mid','att3','att3','att3','mid','box','mid',
'box','att3','box','box','box','mid','att3',
'box','mid','box','box','att3']
})
定义"半场结束前"窗口
# 定义窗口:常规40-45分钟 + 补时(这里用45+补时,简化用40-49)
def is_pre_halftime(minute, window=(40, 49)):
return window[0] <= minute <= window[1]
data['pre_ht'] = data['minute'].apply(is_pre_halftime)
pre_ht = data[data['pre_ht']]
核心统计:攻势强度对比
def attack_stats(df, team):
t = df[df['team']==team]
return {
'射门': (t['event_type']=='shot').sum(),
'射正(xG>0.1)': ((t['event_type']=='shot') & (t['xg']>=0.1)).sum(),
'总xG': round(t['xg'].sum(), 2),
'角球': (t['event_type']=='corner').sum(),
'禁区触球(box)': (t['pitch_zone']=='box').sum(),
'进攻三区(att3)': (t['pitch_zone']=='att3').sum(),
}
for team in ['A','B']:
print(f"--- 球队 {team} 半场结束前(40-49') ---")
print(attack_stats(pre_ht, team))
输出示意:
--- 球队 A 半场结束前(40-49') ---
{'射门': 6, '射正(xG>0.1)': 4, '总xG': 1.35, '角球': 2, '禁区触球(box)': 4, '进攻三区(att3)': 3}
--- 球队 B 半场结束前(40-49') ---
{'射门': 2, '射正(xG>0.1)': 1, '总xG': 0.15, '角球': 1, '禁区触球(box)': 1, '进攻三区(att3)': 0}
→ A队在半场结束前攻势明显占优(射门6-2,xG 1.35 vs 0.15)。
判断"是否加强"(趋势对比)
# 分段:前35分钟 vs 半场结束前
def segment_stats(df, team, start, end):
seg = df[(df['team']==team) & (df['minute'].between(start,end))]
return {
'射门': (seg['event_type']=='shot').sum(),
'xG': round(seg['xg'].sum(),2),
'角球': (seg['event_type']=='corner').sum(),
'box触球': (seg['pitch_zone']=='box').sum()
}
# 单位时间强度对比
early = segment_stats(data,'A',1,39) # 39分钟
late = segment_stats(data,'A',40,49) # 10分钟窗口
# 每分钟强度
for k in ['射门','xG','角球','box触球']:
early_rate = early[k]/39
late_rate = late[k]/10
ratio = late_rate / early_rate if early_rate>0 else np.inf
print(f"{k}: 前段{early_rate:.3f}/min → 末段{late_rate:.3f}/min, 倍数={ratio:.1f}x")
关键:用"每分钟强度"而非绝对数,才能判断"攻势是否加强",若倍数 > 1.5,可判定为半场前攻势加强。
可视化
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(10,4))
for team, color in [('A','red'),('B','blue')]:
t = data[data['team']==team]
shots = t[t['event_type']=='shot']
ax.scatter(shots['minute'], [team]*len(shots),
s=shots['xg']*500, alpha=0.6, c=color)
ax.axvspan(40, 49, alpha=0.15, color='gray', label='半场结束前窗口')
ax.set_xlabel('分钟'); ax.set_title('射门分布(点大小=xG)')
ax.legend(); plt.show()
这样能直观看到半场末段的射门密度和威胁度。
实战中你还需要注意
- 补时问题:45+1、45+2 要用字符串解析,不能只按整数分钟。
- 数据源字段差异:
- StatsBomb →
minute+second,事件类型丰富 - FBref → 分钟级聚合
- 懂球帝/雷速 → 有"危险进攻"字段,可直接用
- StatsBomb →
- 对手强度修正:半场前攻势强 ≠ 优势,要结合比分(落后方会压上)。
- 防守反推:如果对手半场前被压制(本方半场传球多、解围多),反向说明本方攻势。
- 样本量:单场"半场前"只有5-10分钟,数据少,建议多场聚合(如某队赛季平均半场前xG)才有统计意义。
一句话总结
看半场结束前攻势 = 截取 40'~45+补时 事件 → 算射门/xG/角球/禁区触球 → 换算成每分钟强度 → 与前段对比倍数 → 结合比分和对手修正。
如果你能告诉我你手上的数据结构(列名、数据源),我可以帮你写成可直接跑的完整脚本。