Python案例:统计门前抢点射门次数对比
下面用一个完整的案例,演示如何统计不同球员/球队门前抢点射门次数并做对比分析。

数据准备
假设我们有一份足球赛事事件数据(CSV 格式),字段如下:
| 字段 | 说明 |
|---|---|
| match_id | 比赛ID |
| player | 球员姓名 |
| team | 球队 |
| event_type | 事件类型(shot/goal/pass...) |
| shot_type | 射门方式(抢点/远射/头球/点球...) |
| x, y | 射门位置坐标 |
示例数据 shots.csv:
match_id,player,team,event_type,shot_type,x,y 1,武磊,上海海港,shot,抢点,88,45 1,武磊,上海海港,shot,抢点,90,50 1,奥斯卡,上海海港,shot,远射,70,40 2,武磊,上海海港,shot,抢点,85,48 2,张玉宁,北京国安,shot,抢点,89,52 2,张玉宁,北京国安,shot,头球,86,50 3,张玉宁,北京国安,shot,抢点,87,49 3,莱昂纳多,山东泰山,shot,抢点,91,47 4,莱昂纳多,山东泰山,shot,抢点,88,46 4,莱昂纳多,山东泰山,shot,远射,65,35
完整代码
import pandas as pd
import matplotlib.pyplot as plt
# ---------- 1. 设置中文显示 ----------
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# ---------- 2. 读取数据 ----------
df = pd.read_csv('shots.csv')
# ---------- 3. 筛选"门前抢点"射门 ----------
# 只保留 shot 事件 + 抢点方式
grab_shots = df[(df['event_type'] == 'shot') & (df['shot_type'] == '抢点')]
# ---------- 4. 按球员统计抢点次数 ----------
player_grab = (
grab_shots.groupby('player')
.size()
.reset_index(name='抢点次数')
.sort_values('抢点次数', ascending=False)
)
# ---------- 5. 按球队统计抢点次数 ----------
team_grab = (
grab_shots.groupby('team')
.size()
.reset_index(name='抢点次数')
.sort_values('抢点次数', ascending=False)
)
# ---------- 6. 对比:抢点射门 vs 总射门 ----------
total_shots = df[df['event_type'] == 'shot'].groupby('player').size().rename('总射门')
grab_count = grab_shots.groupby('player').size().rename('抢点射门')
compare = pd.concat([total_shots, grab_count], axis=1).fillna(0)
compare['抢点占比(%)'] = (compare['抢点射门'] / compare['总射门'] * 100).round(1)
compare = compare.sort_values('抢点射门', ascending=False)
print("==== 球员抢点射门统计 ====")
print(player_grab)
print("\n==== 球队抢点射门统计 ====")
print(team_grab)
print("\n==== 抢点 vs 总射门对比 ====")
print(compare)
# ---------- 7. 可视化 ----------
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 图1:球员抢点次数柱状图
axes[0].bar(player_grab['player'], player_grab['抢点次数'], color='#E63946')
axes[0].set_title('各球员门前抢点射门次数')
axes[0].set_ylabel('次数')
for i, v in enumerate(player_grab['抢点次数']):
axes[0].text(i, v + 0.05, str(v), ha='center')
# 图2:球员抢点 vs 总射门(分组柱状图)
x = range(len(compare))
axes[1].bar([i - 0.2 for i in x], compare['总射门'], width=0.4, label='总射门', color='#457B9D')
axes[1].bar([i + 0.2 for i in x], compare['抢点射门'], width=0.4, label='抢点射门', color='#E63946')
axes[1].set_xticks(list(x))
axes[1].set_xticklabels(compare.index)
axes[1].set_title('球员抢点射门 vs 总射门')
axes[1].legend()
plt.tight_layout()
plt.savefig('grab_shot_compare.png', dpi=150)
plt.show()
输出结果示例
==== 球员抢点射门统计 ====
player 抢点次数
0 武磊 3
1 张玉宁 2
2 莱昂纳多 2
3 奥斯卡 0
==== 球队抢点射门统计 ====
team 抢点次数
0 上海海港 3
1 北京国安 2
2 山东泰山 2
==== 抢点 vs 总射门对比 ====
总射门 抢点射门 抢点占比(%)
player
武磊 3 3 100.0
张玉宁 3 2 66.7
莱昂纳多 2 2 100.0
奥斯卡 1 0 0.0
进阶扩展
结合射门坐标判断"门前"区域
真实场景中"门前抢点"一般指在小禁区附近(x > 80, 30 < y < 55):
grab_shots = df[
(df['event_type'] == 'shot')
& (df['shot_type'] == '抢点')
& (df['x'] > 80)
& (df['y'].between(30, 55))
]
计算抢点射门转化率(进球率)
if 'is_goal' in df.columns:
grab_df = df[(df['shot_type'] == '抢点')]
conv = grab_df.groupby('player')['is_goal'].agg(['sum', 'count'])
conv['转化率(%)'] = (conv['sum'] / conv['count'] * 100).round(1)
print(conv)
多赛季 / 多球队横向对比(热力图)
import seaborn as sns
pivot = df.pivot_table(
index='player',
columns='team',
values='shot_type',
aggfunc=lambda s: (s == '抢点').sum(),
fill_value=0,
)
sns.heatmap(pivot, annot=True, cmap='Reds', fmt='g')'球员在各队的抢点射门次数')
plt.show()
小结
| 步骤 | 关键 API |
|---|---|
| 筛选抢点射门 | df[(df['shot_type']=='抢点')] |
| 分组统计 | groupby().size() |
| 对比占比 | concat + 除法 |
| 可视化对比 | matplotlib bar / seaborn heatmap |
这个案例可以按需接入真实的 StatsBomb / Opta / 中超官方数据,把 shot_type 替换成实际字段即可复用。
需要我把它改成接入 StatsBomb 开放数据的版本,或者做成网页交互式图表(Plotly)吗?
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播