统计直塞球成功率的实用脚本
下面给你一个完整的 Python 脚本示例,用于统计足球比赛中直塞球(Through Ball)的成功率。

核心指标定义
直塞球成功率 = 成功直塞次数 / 直塞总次数 × 100%
- 成功直塞:球被队友接到,且形成有效进攻(射门/继续控球)
- 失败直塞:被对方拦截、出界、队友未接到
基础版脚本(CSV 数据)
假设你有一份事件数据 events.csv:
match_id,minute,player,team,event_type,outcome M001,12,德布劳内,曼城,through_ball,success M001,25,德布劳内,曼城,through_ball,fail M001,33,京多安,曼城,through_ball,success M001,47,B席,曼城,through_ball,fail M001,58,德布劳内,曼城,through_ball,success
脚本代码
import pandas as pd
# 1. 读取数据
df = pd.read_csv("events.csv")
# 2. 筛选直塞球事件
tb = df[df["event_type"] == "through_ball"].copy()
# 3. 统计成功 / 失败
tb["is_success"] = tb["outcome"] == "success"
total = len(tb)
success = tb["is_success"].sum()
fail = total - success
rate = success / total * 100 if total else 0
# 4. 输出总体结果
print("=" * 40)
print(f"直塞总次数: {total}")
print(f"成功次数: {success}")
print(f"失败次数: {fail}")
print(f"成功率: {rate:.2f}%")
print("=" * 40)
# 5. 按球员统计
player_stats = tb.groupby("player").agg(
直塞次数=("is_success", "size"),
成功次数=("is_success", "sum"),
)
player_stats["成功率(%)"] = (
player_stats["成功次数"] / player_stats["直塞次数"] * 100
).round(2)
player_stats = player_stats.sort_values("成功率(%)", ascending=False)
print("\n【按球员统计】")
print(player_stats)
# 6. 导出结果
player_stats.to_csv("through_ball_stats.csv", encoding="utf-8-sig")
进阶版:加入场地区域和比赛阶段
import pandas as pd
df = pd.read_csv("events.csv")
tb = df[df["event_type"] == "through_ball"].copy()
tb["is_success"] = tb["outcome"] == "success"
# 按球队统计
team_stats = tb.groupby("team").apply(
lambda g: pd.Series({
"直塞次数": len(g),
"成功次数": g["is_success"].sum(),
"成功率(%)": round(g["is_success"].mean() * 100, 2),
})
)
# 按比赛阶段统计(假设有 minute 字段)
def phase(m):
if m <= 30: return "上半场前段"
elif m <= 45: return "上半场后段"
elif m <= 75: return "下半场前段"
else: return "下半场后段"
tb["阶段"] = tb["minute"].apply(phase)
phase_stats = tb.groupby("阶段").agg(
直塞次数=("is_success", "size"),
成功次数=("is_success", "sum"),
)
phase_stats["成功率(%)"] = (phase_stats["成功次数"] / phase_stats["直塞次数"] * 100).round(2)
print("【按球队】\n", team_stats)
print("\n【按阶段】\n", phase_stats)
如果用 StatsBomb / Opta 数据
StatsBomb 示例
from statsbombpy import sb
events = sb.events(match_id=3788741)
# StatsBomb 中直塞球定义为 pass 且 pass_type = "Through Ball"
tb = events[
(events["type"] == "Pass") &
(events["pass_type"].astype(str).str.contains("Through Ball", na=False))
].copy()
tb["success"] = tb["pass_outcome"].isna() # 无 outcome 即为成功
rate = tb["success"].mean() * 100
print(f"直塞球成功率: {rate:.2f}% (样本 {len(tb)} 次)")
Opta 示例
Opta 中直塞球类型码通常是 pass_type = 4(Through Ball),
成功判定看 outcome = 1(成功):
tb = df[(df["type_id"] == 1) & (df["pass_type_id"] == 4)]
tb["success"] = tb["outcome"] == 1
print(f"成功率: {tb['success'].mean()*100:.2f}%")
常见坑与建议
| 问题 | 建议 |
|---|---|
| 样本太小(<10次) | 成功率不可信,需加置信区间 |
| 不同数据源定义不同 | 统一「直塞球」口径后再比较 |
| 中场直塞 vs 禁区直塞 | 分区统计更客观 |
| 领先/落后情况 | 比赛状态会影响冒险程度 |
推荐输出格式
一份完整的直塞球报告应包含:
全队总体成功率
2. 每名球员成功率 + 次数(次数少需标注)
3. 按场地三分区:后场/中场/前场
4. 按比赛阶段:0-15、15-30 ……
5. 成功直塞后续结果:射门/进球/丢球
需要的话,我可以帮你:
- 适配你具体的数据源(WyScout / 中超 / 自定义Excel)
- 加上可视化图表(matplotlib 柱状图、热力图)
- 写一个一键运行的完整工程目录
告诉我你的数据格式即可。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播