Python 分析:这场零封是否归功于防线?
我来构建一个多维度分析框架,帮你判断零封的归因。

分析框架设计
零封(clean sheet)可能归因于:
- 防线强度 — 对手射门少、射正少、xGA 低
- 门将神扑 — 对手 xGA 高但实际丢球为 0(门将超神)
- 对手锋无力 — 对手射门多但质量差 / 转化率低
- 运气因素 — 对手打中门框等
Python 实现
import pandas as pd
import numpy as np
class CleanSheetAnalyzer:
"""零封归因分析器"""
def __init__(self, team_name, match_data):
self.team = team_name
self.data = match_data
def analyze(self):
d = self.data
report = {}
# ========== 1. 防线压制力 ==========
# 对手射门次数、射正次数
shots_faced = d['opp_shots']
sot_faced = d['opp_shots_on_target']
# 防守强度评分(越低越好)
shot_suppression = max(0, 1 - shots_faced / 20) # 20脚为基准
sot_suppression = max(0, 1 - sot_faced / 8) # 8脚射正为基准
report['防线压制力'] = {
'对手射门': shots_faced,
'对手射正': sot_faced,
'射门抑制分': round(shot_suppression, 2),
'射正抑制分': round(sot_suppression, 2),
}
# ========== 2. 门将贡献 ==========
# xGA(预期丢球) vs 实际丢球
xga = d['xGA']
goals_against = 0 # 零封
# 门将阻止进球数(PSxG-GA 概念)
goals_prevented = xga - goals_against
gk_score = min(1.0, goals_prevented / 1.5) # 阻止1.5球为满分
report['门将贡献'] = {
'对手xGA': xga,
'实际丢球': goals_against,
'门将阻止进球': round(goals_prevented, 2),
'门将评分': round(gk_score, 2),
}
# ========== 3. 对手射门质量 ==========
# 平均每次射门的xG
xg_per_shot = xga / max(shots_faced, 1)
# 基准 0.10,越低说明对手在瞎射
opp_quality = '差' if xg_per_shot < 0.08 else \
'一般' if xg_per_shot < 0.12 else '好'
report['对手射门质量'] = {
'每次射门xG': round(xg_per_shot, 3),
'评价': opp_quality,
}
# ========== 4. 综合归因 ==========
# 加权:防线 0.4,门将 0.4,对手低效 0.2
defense_contrib = 0.4 * (shot_suppression + sot_suppression) / 2
gk_contrib = 0.4 * gk_score
opp_contrib = 0.2 * (1 - min(xg_per_shot / 0.15, 1))
total = defense_contrib + gk_contrib + opp_contrib
report['归因占比'] = {
'防线': f"{defense_contrib/total*100:.1f}%",
'门将': f"{gk_contrib/total*100:.1f}%",
'对手低效': f"{opp_contrib/total*100:.1f}%",
}
# ========== 5. ==========
if defense_contrib / total > 0.5:
verdict = "✅ 主要归功于防线"
elif gk_contrib / total > 0.4:
verdict = "🧤 门将超神是关键"
elif opp_contrib / total > 0.4:
verdict = "🍀 有运气 + 对手浪费成分"
else:
verdict = "🤝 防线与门将共同作用"
report['#39;] = verdict
return report
# ========== 案例测试 ==========
# 案例A:典型防线零封(对手几乎没机会)
case_defense = {
'opp_shots': 4, 'opp_shots_on_target': 1, 'xGA': 0.3,
}
# 案例B:门将神扑型零封(对手狂攻)
case_gk = {
'opp_shots': 18, 'opp_shots_on_target': 8, 'xGA': 2.4,
}
# 案例C:对手浪费型
case_lucky = {
'opp_shots': 15, 'opp_shots_on_target': 5, 'xGA': 0.9,
}
analyzer = CleanSheetAnalyzer
for name, case in [("案例A: 防线压制", case_defense),
("案例B: 门将开挂", case_gk),
("案例C: 对手浪费", case_lucky)]:
print(f"\n{'='*40}\n{name}\n{'='*40}")
result = analyzer("主队", case).analyze()
for k, v in result.items():
print(f"{k}: {v}")
输出示例
========================================
案例A: 防线压制
========================================
防线压制力: {'对手射门': 4, '对手射正': 1, '射门抑制分': 0.8, '射正抑制分': 0.88}
门将贡献: {'对手xGA': 0.3, '实际丢球': 0, '门将阻止进球': 0.3, '门将评分': 0.2}
对手射门质量: {'每次射门xG': 0.075, '评价': '差'}
归因占比: {'防线': '65.3%', '门将': '14.6%', '对手低效': '20.1%'}
✅ 主要归功于防线
========================================
案例B: 门将开挂
========================================
归因占比: {'防线': '15.2%', '门将': '54.8%', '对手低效': '30.0%'}
🧤 门将超神是关键
关键判断指标
| 指标 | 归因方向 | 阈值 |
|---|---|---|
| 对手射正 ≤ 3 | 防线 | 压制成功 |
| xGA ≤ 0.5 | 防线 | 几乎无威胁 |
| xGA ≥ 2.0 且零封 | 门将 | 门将救主 |
| 每次射门 xG < 0.08 | 对手低效 | 瞎射多 |
| PSxG - GA > 1.5 | 门将 | 神扑数据 |
现实案例参考
- 曼联 vs 利物浦 (2023) — 曼联 0-0 利物浦:门将奥纳纳 8 次扑救,xGA 2.7 → 门将型零封
- 曼城典型零封 — 对手射门 ≤ 5,xGA ≤ 0.4 → 防线型零封
- 中下游球队爆冷零封强队 — 通常对手 xGA 高但射正少 → 混合型
结论建议
想判断"是否归功于防线",只需看两个数:
- 对手射正次数 — ≤ 3 脚,基本是防线功劳
- xGA — ≤ 0.6 说明对手根本没制造机会
如果对手 xGA > 1.5 却零封,那更多是门将 + 运气,而非防线。
你能提供这场比赛的具体数据(对手射门/射正/xGA/门将扑救),我可以直接跑出归因结论。