足球单刀球成功率统计案例
下面我用 Python 模拟统计足球比赛中"单刀球"的成功率,包含数据模拟、统计分析和可视化。

完整代码案例
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# ========== 1. 模拟数据 ==========
np.random.seed(42)
players = ['梅西', 'C罗', '姆巴佩', '哈兰德', '凯恩',
'萨拉赫', '本泽马', '莱万', '内马尔', '维尼修斯']
data = []
for player in players:
# 每名球员单刀球总次数(10-30次)
total = np.random.randint(10, 31)
# 单刀进球数(成功率约 30%~65%)
success_rate = np.random.uniform(0.30, 0.65)
goals = int(round(total * success_rate))
data.append({
'球员': player,
'单刀总次数': total,
'单刀进球数': goals
})
df = pd.DataFrame(data)
# ========== 2. 计算成功率 ==========
df['成功率(%)'] = (df['单刀进球数'] / df['单刀总次数'] * 100).round(2)
# 按成功率排序
df = df.sort_values('成功率(%)', ascending=False).reset_index(drop=True)
print("=" * 55)
print(" 单刀球成功率统计表")
print("=" * 55)
print(df.to_string(index=False))
# ========== 3. 整体统计 ==========
total_shots = df['单刀总次数'].sum()
total_goals = df['单刀进球数'].sum()
overall_rate = total_goals / total_shots * 100
print("\n" + "=" * 55)
print(f"总单刀次数 : {total_shots} 次")
print(f"总单刀进球数 : {total_goals} 个")
print(f"整体单刀成功率 : {overall_rate:.2f}%")
print(f"最高成功率 : {df['成功率(%)'].max():.2f}% ({df.iloc[0]['球员']})")
print(f"最低成功率 : {df['成功率(%)'].min():.2f}% ({df.iloc[-1]['球员']})")
print(f"平均成功率 : {df['成功率(%)'].mean():.2f}%")
print("=" * 55)
# ========== 4. 可视化 ==========
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
# 图1:各球员成功率柱状图
colors = ['#2ecc71' if x >= overall_rate else '#e74c3c' for x in df['成功率(%)']]
axes[0].bar(df['球员'], df['成功率(%)'], color=colors)
axes[0].axhline(overall_rate, color='blue', linestyle='--',
label=f'整体平均 {overall_rate:.1f}%')
axes[0].set_title('各球员单刀球成功率', fontsize=14)
axes[0].set_ylabel('成功率 (%)')
axes[0].set_xticklabels(df['球员'], rotation=45)
axes[0].legend()
axes[0].grid(axis='y', alpha=0.3)
# 图2:单刀次数 vs 进球数
x = np.arange(len(df))
width = 0.35
axes[1].bar(x - width/2, df['单刀总次数'], width, label='单刀总次数', color='#3498db')
axes[1].bar(x + width/2, df['单刀进球数'], width, label='单刀进球数', color='#f39c12')
axes[1].set_xticks(x)
axes[1].set_xticklabels(df['球员'], rotation=45)
axes[1].set_title('单刀总次数 vs 进球数', fontsize=14)
axes[1].legend()
axes[1].grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig('单刀球成功率统计.png', dpi=100, bbox_inches='tight')
plt.show()
运行结果示例
=======================================================
单刀球成功率统计表
=======================================================
球员 单刀总次数 单刀进球数 成功率(%)
凯恩 16 10 62.50
萨拉赫 25 15 60.00
哈兰德 28 16 57.14
梅西 22 12 54.55
本泽马 29 15 51.72
莱万 19 9 47.37
内马尔 12 5 41.67
姆巴佩 24 9 37.50
维尼修斯 18 6 33.33
C罗 15 5 33.33
=======================================================
总单刀次数 : 208 次
总单刀进球数 : 102 个
整体单刀成功率 : 49.04%
最高成功率 : 62.50% (凯恩)
最低成功率 : 33.33% (C罗)
平均成功率 : 47.91%
=======================================================
关键知识点解析
成功率计算公式
成功率 = 单刀进球数 / 单刀总次数 × 100%
核心 Pandas 操作
| 操作 | 代码 |
|---|---|
| 计算列 | df['进球数'] / df['总次数'] |
| 四舍五入 | .round(2) |
| 排序 | .sort_values('成功率', ascending=False) |
| 汇总求和 | .sum() |
| 求平均 | .mean() |
真实场景扩展建议
如果要处理真实比赛数据,可以补充以下字段:
# 扩展数据字段示例
df_advanced = pd.DataFrame({
'球员': ['梅西', 'C罗'],
'单刀总次数': [22, 15],
'单刀进球数': [12, 5],
'射门角度': [35, 42], # 平均射门角度
'门将出击距离': [5.2, 6.8], # 门将出击距离(米)
'比赛阶段': ['上半场', '下半场'],
'射门脚': ['左脚', '右脚'],
})
可进一步分析:
- 📊 分时段成功率:上半场 vs 下半场
- 🦶 不同射门脚:左脚、右脚、头球的成功率差异
- 🥅 门将类型影响:出击型门将 vs 门线型门将
- 📈 趋势分析:按月/赛季统计成功率变化
加置信区间(进阶)
样本量较小时,成功率波动大,可用二项分布置信区间估计:
from scipy.stats import beta
def wilson_ci(success, total, confidence=0.95):
"""Wilson 置信区间(小样本更稳定)"""
z = 1.96 # 95% 置信度
p = success / total
denom = 1 + z**2 / total
center = (p + z**2 / (2*total)) / denom
margin = z * np.sqrt(p*(1-p)/total + z**2/(4*total**2)) / denom
return (center - margin) * 100, (center + margin) * 100
df['CI_下'] , df['CI_上'] = zip(*df.apply(
lambda r: wilson_ci(r['单刀进球数'], r['单刀总次数']), axis=1))
print(df[['球员', '成功率(%)', 'CI_下', 'CI_上']])
这样可以避免"5次射门进3球 = 60%"这类小样本造成的误判——置信区间会告诉你真实水平可能只有 20%~90%。
真实足球统计中,单刀球成功率通常在 40%~55% 之间浮动,顶级射手可达 60%+,本案例演示了用 Pandas 做分组统计 + 可视化的完整流程,需要我改成读取真实 CSV 文件版本,或加入置信区间可视化,可以继续告诉我 👍
版权声明:本站文章为原创整理,转载请注明出处。