python案例如何解读后防线的xG against?

wen python案例 4

解读后防线的 xG Against(预期失球)

在足球数据分析中,xG Against(xGA) 是评估后防线质量的核心指标之一,下面从概念、数据获取、案例代码到解读方法完整讲一遍。

python案例如何解读后防线的xG against?


概念先行

指标 含义 解读方向
xG 预期进球,衡量射门质量 越高代表机会越好
xGA (xG Against) 对手在你球门前创造的预期进球总和 越低越好,反映防守质量
xGA/90 每90分钟失球预期 归一化对比
PSxG 射门后预期进球(考虑门将) 区分门将与后防贡献
Goals - xGA 实际失球 - 预期失球 正=运气差/门将差,负=运气好/门将神勇

关键要点:xGA 衡量的是机会质量,不是结果,一支球队可能丢球少但 xGA 高(门将救险多),也可能丢球多但 xGA 低(运气差)。


Python 数据获取(以 statsbomb / understat 为例)

方案 A:用 soccerdata 抓 Understat 数据

# pip install soccerdata
import soccerdata as sd
import pandas as pd
# 抓取英超某赛季球队数据
understat = sd.Understat(leagues="ENG-Premier League", seasons=2023)
team_stats = understat.read_team_season_stats(stat_type="defense")
print(team_stats.head())
# 常见列: xGA, goals_conceded, clean_sheet, ppda ...

方案 B:StatsBomb 开放数据自己算 xGA

from statsbombpy import sb
events = sb.events(match_id=3788741)  # 某场比赛
# 提取对手射门(假设主队是分析对象)
shots = events[events['type'] == 'Shot'].copy()
shots['shot_statsbomb_xg'] = shots['shot_statsbomb_xg'].fillna(0)
xga = shots.groupby('team')['shot_statsbomb_xg'].sum()
print(xga)  # 每队被射门的 xG 总和 = 该队防线的 xGA

注意:StatsBomb 的 shot_statsbomb_xg 是射门方视角的 xG,被射门方视角就是 xGA。


后防线 xGA 案例解读(完整流程)

赛季对比:找出防守最好/最差球队

import matplotlib.pyplot as plt
# team_stats 含列: xGA, goals_conceded
df = team_stats.reset_index()
df['xGA_per90'] = df['xGA'] / df['matches'] 
df['goals_minus_xGA'] = df['goals_conceded'] - df['xGA']  # 门将/运气修正
df_sorted = df.sort_values('xGA_per90')
print(df_sorted[['team', 'xGA_per90', 'goals_minus_xGA']].head(10))

解读示例:

  • xGA/90 低 → 后防线有效限制了对手高质量机会(结构、压迫、站位好)。
  • goals_minus_xGA 为负(失球 < xGA) → 门将扑救超常 或 对手射术差 或 运气好。
  • goals_minus_xGA 为正(失球 > xGA) → 门将拉胯 / 运气差,但后防线本身未必差。

区分"后防问题"还是"门将问题"

# 用 PSxG 分离门将贡献(需 FBref 数据)
# PSxG - Goals Conceded = 门将扑救价值
df['gk_contribution'] = df['psxg'] - df['goals_conceded']
# 后防真实质量 ≈ xGA - 门将超出预期部分
df['defensive_quality'] = df['xGA'] - df['gk_contribution'] * 0.0  # 概念示意

核心逻辑:

实际失球 = 后防允许的机会(xGA) - 门将扑救价值(PSxG - GA)
  • xGA 高 + PSxG-GA 高 → 门将神勇掩盖后防漏洞(隐患)。
  • xGA 低 + PSxG-GA 低 → 后防扎实,门将正常。
  • xGA 高 + PSxG-GA 低 → 后防真差,门将也救不了。

逐场分布看稳定性

# 假设有逐场数据 match_df: [date, team, xGA]
import seaborn as sns
pivot = match_df.pivot_table(index='date', columns='team', values='xGA')
sns.boxplot(data=match_df, x='team', y='xGA')
plt.xticks(rotation=90)'各队逐场 xGA 分布')

解读:

  • 中位数低、箱体窄 → 防守稳定且优秀。
  • 中位数低但箱体大 → 平均值漂亮但偶有崩盘(如被打反击)。
  • 长尾上须长 → 存在被大比分打穿的场次,需查具体对手/战术。

结合对手强度(xGA 需上下文)

# 对阵强队 xGA 高是合理的,用对手平均 xG 做校正
df['xGA_vs_expected'] = df['xGA'] - df['opp_avg_xg'] * df['matches']

一支球队对阵曼城 xGA=2.0 不算差,对阵保级队 xGA=1.5 才算差。必须做对手强度校正。


解读时的常见陷阱

  1. xGA 低 ≠ 防守好:可能是低位大巴 + 门将超神,长期不可持续。
  2. 样本量:赛季初 5 场 xGA 波动大,至少 10 场以上再下结论。
  3. xG 模型差异:不同数据商(StatsBomb / Opta / Understat)xG 模型不同,横向对比需同源。
  4. 定位球未分离:很多平台的 xGA 含定位球,评估"运动战后防"时要拆开 set_piece_xga。
  5. 红牌/少打一人场次会污染数据,分析前过滤。

一句话总结解读框架

先看 xGA/90 定位防守基线 → 用 Goals−xGA 判断门将/运气 → 用逐场分布看稳定性 → 用对手强度校正 → 拆分定位球找具体短板。

这样一套 Python 流程下来,后防线的 xGA 就不只是一个数字,而是能讲出"是结构问题、门将问题还是运气问题"的完整诊断,需要我针对某支具体球队(比如某赛季阿森纳/曼城)跑一遍完整案例吗?

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