本文目录导读:

- 方案一:使用
statsbombpy(免费API,顶级赛事数据) - 方案二:使用
mplsoccer(适用于 Wyscout/Understat 数据) - 方案三:通用脚本(从 CSV / 自定义数据计算)
- 关键注意点(非常重要)
在足球数据分析中,“禁区内射门”通常指的是射门发生时,皮球所在位置处于对方罚球区(大禁区)内。
针对你的需求,我提供三个不同场景的实用脚本(Python + 开源数据),请根据你的数据来源选择最合适的。
使用 statsbombpy(免费API,顶级赛事数据)
这是目前获取最详细事件数据最简单的方式,数据中自带 shot_end_location(射门结束位置),但由于我们需要“禁区内”,应使用 location(射门起始位置)。
import pandas as pd
from statsbombpy import sb
# 1. 加载数据(以2018世界杯决赛法国 vs 克罗地亚为例)
# 免费API数据ID:比赛ID 8658
df_events = sb.events(match_id=8658)
# 2. 过滤出射门事件
shots = df_events[(df_events['type'] == 'Shot')].copy()
# 3. 提取射门位置的坐标(StatsBomb坐标系:x为0-120,y为0-80)
# 注意:坐标原点在防守方半场,进攻方向为从左向右
shots['x'] = shots['location'].apply(lambda loc: loc[0] if loc else None)
shots['y'] = shots['location'].apply(lambda loc: loc[1] if loc else None)
# 4. 判断是否在禁区内(对方球门为120,禁区线为102)
# 同时考虑左右两个半场(即进攻方向)
def is_in_box(row):
if row['x'] <= 60: # 攻右路
return (row['x'] >= 18) and (18 <= row['y'] <= 62)
else: # 攻左路
return (row['x'] >= 102) and (18 <= row['y'] <= 62)
shots['in_box'] = shots.apply(is_in_box, axis=1)
# 5. 统计对比
# 确定球队(home_team / away_team)
result = shots.groupby(['team', 'in_box']).size().unstack(fill_value=0)
result.columns = ['禁区外射门', '禁区内射门']
result['总射门'] = result.sum(axis=1)
print(result)
使用 mplsoccer(适用于 Wyscout/Understat 数据)
如果你使用的是 Wyscout 或 Understat 的公开数据(通常坐标是0-100),坐标逻辑不同(x=100是对方球门)。mplsoccer 内置了画球场功能,可以直观验证。
import pandas as pd
from mplsoccer import Pitch
# 假设你已经有了 shots_df,包含 'x'(射门起点x坐标0-100), 'y',和'team'
# 数据示例:
# shots_df = pd.DataFrame({'x': [85, 50, 92], 'y': [40, 20, 35], 'team': ['A', 'B', 'A']})
def is_box_mpl(row):
# 坐标0-100,球门在x=100
# 大禁区范围(近似):x > 82.5 且 21 < y < 79
return (row['x'] > 82.5) and (21 < row['y'] < 79)
# 假设主队列名为 'home_team',客队为 'away_team'
shots_df['is_box'] = shots_df.apply(is_box_mpl, axis=1)
# 统计
summary = shots_df.groupby(['team', 'is_box']).size().unstack(fill_value=0)
summary.columns = ['Out', 'In']
print(summary)
# 可视化(可选):画一个带射门点的球场
pitch = Pitch(pitch_type='statsbomb', line_color='black')
fig, ax = pitch.draw()
# 按是否在禁区内着色
for idx, row in shots_df.iterrows():
color = 'red' if row['is_box'] else 'blue'
pitch.scatter(row['x'], row['y'], ax=ax, color=color, s=50)
通用脚本(从 CSV / 自定义数据计算)
如果你有标准的事件数据(列:team, x_start, y_start),可以用最精简的纯Pandas脚本:
import pandas as pd
# 读取你的数据
df = pd.read_csv('your_events.csv')
# 标准足球场坐标(x: 0-100, y: 0-100, 球门在 x=100)
# 调整你的坐标轴如果数据是 0-120 的
df['in_box'] = (df['x_start'] > 82.5) & (df['y_start'] > 21) & (df['y_start'] < 79)
# 按球队和是否在禁区内统计
result = df.groupby(['team', 'in_box']).size().unstack(fill_value=0)
# 重命名
result.columns = ['Box_Shots', 'Out_Box_Shots']
print(result)
# 如果想输出百分比
result['Box_Percentage'] = result['Box_Shots'] / (result['Box_Shots'] + result['Out_Box_Shots']) * 100
print(result)
关键注意点(非常重要)
- 坐标方向:不同的数据公司(StatsBomb / Opta / Wyscout)坐标系不一样。
- StatsBomb:
x范围 0~120,y范围 0~80,本方球门在 (0, 40)。 - Wyscout / Understat:
x范围 0~100,y范围 0~100,对方球门在 (100, 50)。
- StatsBomb:
- 判别逻辑:禁区是一个矩形区域,判断条件是
x超过大禁区线,且y在禁区宽度内,对于左右两个半场分别判断。 - “禁区内”通常指:射门发生在对方罚球区(18码区)内,不包括点球点附近的小禁区(通常点球不计入运动战射门)。
如果你能告诉我你的数据来源(是某网站爬下来的Excel,还是API),我可以帮你改成完全适配的版本。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播