Python 案例:统计长短传比例分布
下面通过几个不同场景的案例,演示如何统计"长传/短传"比例并分析分布。

案例1:基础足球传球数据统计
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 构造模拟传球数据
np.random.seed(42)
data = {
'player': np.random.choice(['A', 'B', 'C', 'D'], 500),
'distance': np.random.gamma(2, 8, 500), # 传球距离(米)
}
df = pd.DataFrame(data)
# 定义长短传阈值(如15米)
THRESHOLD = 15
df['type'] = df['distance'].apply(lambda x: '长传' if x >= THRESHOLD else '短传')
# 全局比例
ratio = df['type'].value_counts(normalize=True)
print("=== 全局长短传比例 ===")
print(ratio.round(3))
# 每个球员的比例
by_player = df.groupby('player')['type'].value_counts(normalize=True).unstack(fill_value=0)
print("\n=== 各球员长短传比例 ===")
print(by_player.round(3))
案例2:距离分箱后的分布直方图
# 传球距离分布(直方图)
plt.figure(figsize=(10, 4))
plt.subplot(1, 2, 1)
df['distance'].hist(bins=30, edgecolor='black')
plt.axvline(THRESHOLD, color='red', linestyle='--', label=f'阈值 {THRESHOLD}m')'传球距离分布')
plt.xlabel('距离(米)')
plt.ylabel('次数')
plt.legend()
# 比例柱状图
plt.subplot(1, 2, 2)
ratio.plot(kind='bar', color=['steelblue', 'orange'])'长传/短传比例')
plt.ylabel('比例')
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()
案例3:按距离区间(bins)统计分布
# 按距离区间分段统计
bins = [0, 5, 10, 15, 25, 40, 100]
labels = ['0-5m', '5-10m', '10-15m', '15-25m', '25-40m', '40m+']
df['bin'] = pd.cut(df['distance'], bins=bins, labels=labels)
bin_dist = df['bin'].value_counts().sort_index()
bin_pct = (bin_dist / len(df) * 100).round(1)
print("=== 距离区间分布 ===")
summary = pd.DataFrame({'次数': bin_dist, '占比%': bin_pct})
print(summary)
# 柱状图
bin_pct.plot(kind='bar', color='teal', figsize=(8, 4))'传球距离区间分布')
plt.ylabel('占比 (%)')
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()
案例4:含时间维度的长短传趋势(比赛分阶段)
# 加入比赛分钟
df['minute'] = np.random.randint(1, 91, len(df))
# 按15分钟分段
df['period'] = pd.cut(df['minute'],
bins=[0, 15, 30, 45, 60, 75, 90],
labels=['0-15', '15-30', '30-45', '45-60', '60-75', '75-90'])
period_ratio = (df.groupby(['period', 'type'], observed=True)
.size()
.unstack(fill_value=0))
period_ratio['长传比例'] = period_ratio['长传'] / period_ratio.sum(axis=1)
print("=== 各阶段传球比例 ===")
print(period_ratio.round(3))
# 折线图
period_ratio['长传比例'].plot(marker='o', figsize=(8, 4))'各时段长传比例变化')
plt.ylabel('长传占比')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
案例5:完整流程封装函数
def analyze_pass_distribution(df, dist_col='distance', threshold=15, group_col=None):
"""
统计长短传比例分布
返回:全局比例、分箱分布、分组比例(可选)
"""
df = df.copy()
df['type'] = np.where(df[dist_col] >= threshold, '长传', '短传')
overall = df['type'].value_counts(normalize=True)
bins = [0, 5, 10, threshold, 25, 40, np.inf]
labels = [f'0-5m', f'5-10m', f'10-{threshold}m',
f'{threshold}-25m', '25-40m', '40m+']
df['bin'] = pd.cut(df[dist_col], bins=bins, labels=labels)
bin_dist = df['bin'].value_counts(normalize=True).sort_index()
grouped = None
if group_col:
grouped = (df.groupby(group_col)['type']
.value_counts(normalize=True)
.unstack(fill_value=0))
return {
'overall': overall,
'by_bin': bin_dist,
'by_group': grouped
}
result = analyze_pass_distribution(df, group_col='player')
print(result['overall'].round(3))
print(result['by_bin'].round(3))
print(result['by_group'].round(3))
关键要点
| 要点 | 说明 |
|---|---|
| 阈值定义 | 长传阈值常见为 15/20/25 米(依联赛或战术标准) |
| 比例计算 | value_counts(normalize=True) 快速求占比 |
| 分布分析 | 用 pd.cut 分箱后统计,比单一阈值更有洞察力 |
| 多维对比 | 按球员/时段/场次分组更能反映战术差异 |
| 可视化 | 直方图看原始分布,柱状图看区间占比,折线图看趋势 |
需要我针对真实比赛数据(如 StatsBomb / Opta)、篮球长短传或其他领域(如网络传输包大小)的变体案例继续展开吗?