本文目录导读:

在足球数据分析中,进攻三区通常指距离对方底线约1/3的场地区域,也就是前场35米左右的范围,量化进攻三区效率值,核心思路是:衡量球队/球员进入该区域后,转化为实质性威胁的能力。
下面是一套可直接落地的实用脚本设计框架。
效率值定义框架
核心公式
进攻三区效率值 = (加权威胁产出 / 进攻三区触球或进入次数) × 标准化系数
分层指标
| 层级 | 指标 | 权重建议 |
|---|---|---|
| 产出层 | 进球、助攻、射门、关键传球、xG、xA | 高 |
| 过程层 | 传入禁区、成功过人、推进传球 | 中 |
| 基础层 | 进攻三区触球数、进入次数 | 分母 |
数据源准备
# 常用数据源 # - StatsBomb Open Data (免费, 事件级) # - Opta / Stats Perform (付费) # - FBref (免费, 聚合数据) # - Wyscout (付费) # - 自建: 视频追踪 + 标注 import pandas as pd import numpy as np # 假设事件数据格式(StatsBomb风格) # columns: match_id, player, team, event_type, x, y, end_x, end_y, outcome
核心脚本
判定进攻三区
def is_final_third(x, pitch_length=105):
"""x为沿进攻方向的坐标(0=己方底线, 105=对方底线)"""
return x >= pitch_length * 2 / 3 # 前1/3
def is_penalty_area(x, y, pitch_length=105, pitch_width=68):
"""对方禁区: x>=88.5, 13.84<=y<=54.16"""
return x >= 88.5 and 13.84 <= y <= 54.16
计算单次进攻三区行为的威胁权重
def action_threat_weight(row):
"""给每次进攻三区行为赋威胁权重"""
w = 0
if row['event_type'] == 'Shot':
w += 0.3 + 0.7 * row.get('xg', 0) # 射门
if row['event_type'] == 'Pass':
if row.get('is_key_pass'):
w += 0.5
if row.get('end_in_box'):
w += 0.3
if row.get('is_assist'):
w += 0.8
if row['event_type'] == 'Carry':
w += 0.1 * row.get('progression', 1)
if row['event_type'] == 'Dribble' and row.get('success'):
w += 0.2
return w
主计算函数
def final_third_efficiency(events_df, entity='team', min_actions=20):
"""
计算进攻三区效率值
entity: 'team' 或 'player'
"""
df = events_df.copy()
df = df[df.apply(lambda r: is_final_third(r['x']), axis=1)]
df['threat'] = df.apply(action_threat_weight, axis=1)
# 分子: 加权威胁总和
agg = df.groupby(entity).agg(
threat_sum=('threat', 'sum'),
actions=('threat', 'count'),
shots=('event_type', lambda s: (s=='Shot').sum()),
goals=('is_goal', 'sum'),
xg=('xg', 'sum') if 'xg' in df else ('threat', 'size')
).reset_index()
# 效率值 = 每次进攻三区行为的平均威胁产出
agg['ft_efficiency'] = agg['threat_sum'] / agg['actions']
# 标准化到 0-100 (相对同位置/同联赛)
agg['ft_efficiency_norm'] = (
(agg['ft_efficiency'] - agg['ft_efficiency'].min()) /
(agg['ft_efficiency'].max() - agg['ft_efficiency'].min()) * 100
)
# 过滤样本不足
agg = agg[agg['actions'] >= min_actions]
return agg.sort_values('ft_efficiency', ascending=False)
调用示例
# 读取事件数据
events = pd.read_csv('events.csv')
# 按球队计算
team_eff = final_third_efficiency(events, entity='team')
# 按球员计算
player_eff = final_third_efficiency(events, entity='player', min_actions=30)
print(team_eff[['team', 'ft_efficiency', 'ft_efficiency_norm', 'goals', 'xg']])
进阶版本:加入情境修正
对手强度修正
def adjust_by_opponent(df, opp_strength):
"""opp_strength: dict {对手: 0-1 强度}"""
df['opp_factor'] = df['opponent'].map(opp_strength).fillna(0.5)
df['adjusted_threat'] = df['threat'] * (1 + df['opp_factor'])
return df
比分情境修正
def adjust_by_scoreline(df):
"""落后时进攻三区行为含金量更高"""
weight = { 'leading': 0.9, 'drawing': 1.0, 'trailing': 1.2 }
df['score_factor'] = df['score_state'].map(weight)
df['adjusted_threat'] = df['threat'] * df['score_factor']
return df
最终效率值
FTE = (Σ 加权威胁 × 对手系数 × 比分系数) / 进攻三区进入次数 × 100
可视化输出
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(10, 6))
ax.barh(team_eff['team'], team_eff['ft_efficiency_norm'])
ax.set_xlabel('进攻三区效率值 (标准化)')
ax.set_title('各队进攻三区效率对比')
plt.tight_layout()
plt.savefig('ft_efficiency.png', dpi=150)
实战注意事项
- 分母选择:用“进攻三区触球数”比“进入次数”更稳定,避免单次长传造成的噪声。
- 样本量:球员至少 30 次进攻三区行为,球队至少 5 场比赛。
- 位置归一:边锋和中锋的效率基准不同,建议分位置标准化。
- xG/xA 优先:有 xG 数据时,用 xG 替代进球数,抗运气干扰。
- 防守强度:可引入 PPDA(对手每次防守动作传球数)作为对手强度代理。
可直接用的最小 MVP
如果你只有基础数据(传球、射门位置),最小可行版本:
def mvp_fte(df):
ft = df[df['x'] >= 70] # 进攻三区
return ft.groupby('team').apply(
lambda g: (g['shots'].sum() * 1 + g['key_passes'].sum() * 0.5) / len(g)
).sort_values(ascending=False)
需要我根据你手上的具体数据格式(StatsBomb JSON、Opta CSV、或自建表结构)写一版完整可跑的脚本吗?告诉我字段名即可。