Python案例:统计"落叶球"射门成功率
下面用几个Python案例,从简单到进阶,演示如何统计足球比赛中落叶球(knuckleball / dipping shot)射门的成功率。

数据准备
先模拟一份射门数据(真实场景可从Opta、StatsBomb等数据源获取):
import pandas as pd
import numpy as np
np.random.seed(42)
# 模拟 200 次射门记录
data = {
"shot_id": range(1, 201),
"player": np.random.choice(["梅西", "C罗", "德布劳内", "皮尔洛", "贝克汉姆"], 200),
"shot_type": np.random.choice(
["落叶球", "弧线球", "抽射", "推射"],
size=200,
p=[0.2, 0.3, 0.25, 0.25]
),
"distance": np.round(np.random.uniform(16, 35, 200), 1), # 射门距离(米)
"is_goal": np.random.choice([0, 1], size=200, p=[0.85, 0.15]) # 是否进球
}
df = pd.DataFrame(data)
print(df.head())
案例1:总体成功率统计
# 按射门方式分组,统计次数、进球数、成功率
stats = df.groupby("shot_type").agg(
射门次数=("is_goal", "count"),
进球数=("is_goal", "sum"),
成功率=("is_goal", "mean")
).round(3)
stats["成功率"] = (stats["成功率"] * 100).astype(str) + "%"
print(stats)
输出示例:
射门次数 进球数 成功率
shot_type
抽射 52 8 15.4%
推射 47 6 12.8%
弧线球 61 9 14.8%
落叶球 40 7 17.5%
案例2:结合距离区间分析
落叶球通常从远距离射门威胁大,因此按距离分段更科学:
# 划分距离区间
bins = [0, 20, 25, 30, 100]
labels = ["近距离(<20m)", "中距离(20-25m)", "远距离(25-30m)", "超远(>30m)"]
df["distance_zone"] = pd.cut(df["distance"], bins=bins, labels=labels)
# 只看落叶球
knuckle = df[df["shot_type"] == "落叶球"]
result = knuckle.groupby("distance_zone").agg(
射门次数=("is_goal", "count"),
进球数=("is_goal", "sum"),
成功率=("is_goal", "mean")
).round(3)
result["成功率"] = (result["成功率"] * 100).round(1).astype(str) + "%"
print(result)
案例3:计算置信区间(更严谨)
小样本时成功率波动大,可用 Wilson 区间估计:
from statsmodels.stats.proportion import proportion_confint
def success_rate_ci(success, total, alpha=0.05):
low, high = proportion_confint(success, total, alpha=alpha, method="wilson")
return round(success/total*100, 1), round(low*100, 1), round(high*100, 1)
knuckle = df[df["shot_type"] == "落叶球"]
n = len(knuckle)
k = knuckle["is_goal"].sum()
rate, low, high = success_rate_ci(k, n)
print(f"落叶球成功率: {rate}% (95% CI: {low}% ~ {high}%)")
落叶球成功率: 17.5% (95% CI: 8.7% ~ 32.0%)说明样本少时不能只看点估计。
案例4:可视化对比
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False
stats = df.groupby("shot_type")["is_goal"].mean() * 100
stats.sort_values().plot(kind="barh", color="steelblue", figsize=(8, 4))"各射门方式成功率对比")
plt.xlabel("成功率 (%)")
plt.tight_layout()
plt.show()
进阶:用贝叶斯做小样本估计
当某球员落叶球样本很少时,可用 Beta 先验:
from scipy.stats import beta
# 先验:假设整体落叶球成功率约 15%
a_prior, b_prior = 15, 85
# 某球员数据
player_shots, player_goals = 8, 2
a_post = a_prior + player_goals
b_post = b_prior + (player_shots - player_goals)
mean = a_post / (a_post + b_post)
print(f"贝叶斯估计成功率: {mean*100:.1f}%")
业务结论示例
综合以上分析可以得出:
| 结论点 | 说明 |
|---|---|
| 落叶球成功率 | 约 15%~18%,略高于其他射门方式 |
| 距离影响 | 25-30m 远射效率最高(门将难判断) |
| 样本问题 | 单赛季样本少,需用置信区间或贝叶斯 |
| 球员差异 | 需按球员分层,避免辛普森悖论 |
统计落叶球成功率的核心步骤:
- 数据清洗 → 标注射门类型
- 分组聚合 →
groupby + agg - 区间分析 → 按距离/角度分层
- 统计严谨性 → 置信区间 / 贝叶斯
- 可视化 & 结论
如果需要,我可以进一步给出:
- 用 StatsBomb 开放数据 实战的真实代码
- 加入 xG(预期进球) 对比落叶球是否"超常发挥"
- 用 逻辑回归 建模预测落叶球进球概率
告诉我你更想深入哪一块?