实用脚本统计长短传比例如何分布?

wen 实用脚本 2

统计长短传比例分布的实用脚本

下面给你一套可直接用的脚本,覆盖 Python(pandas)、SQL、Shell 三种场景,适合统计长传/短传比例及其分布。

实用脚本统计长短传比例如何分布?


先明确口径(关键)

统计前必须定义清楚,否则结果没意义:

项目 常见口径
短传 传球距离 < 30m(或 < 25m)
长传 传球距离 ≥ 30m
比例 长传数 / 总传球数,或 长传/短传
分布 按球员、按球队、按比赛、按区间桶分布

下面脚本默认:短传 <30m,长传 ≥30m,字段名假设为 player_id, team_id, match_id, pass_distance。


Python + pandas 脚本

基础比例 + 分布

import pandas as pd
import numpy as np
# 读取数据
df = pd.read_csv("passes.csv")   # 列: player_id, team_id, match_id, pass_distance
SHORT_TH = 30  # 短传阈值(米)
df["pass_type"] = np.where(df["pass_distance"] < SHORT_TH, "short", "long")
# ---- 按球员统计 ----
def ratio_stats(g):
    total = len(g)
    short = (g["pass_type"] == "short").sum()
    long_ = (g["pass_type"] == "long").sum()
    return pd.Series({
        "total": total,
        "short": short,
        "long": long_,
        "short_ratio": short / total,
        "long_ratio": long_ / total,
        "long_short_ratio": long_ / short if short else np.nan,
    })
player_stats = df.groupby("player_id").apply(ratio_stats).reset_index()
print(player_stats.head())
# ---- 按球队统计 ----
team_stats = df.groupby("team_id").apply(ratio_stats).reset_index()
# ---- 按比赛统计 ----
match_stats = df.groupby("match_id").apply(ratio_stats).reset_index()

分布直方图(比例如何分布)

import matplotlib.pyplot as plt
# 球员长传比例分布
plt.figure(figsize=(8,5))
plt.hist(player_stats["long_ratio"], bins=np.arange(0, 1.05, 0.05),
         edgecolor="black")
plt.xlabel("Long pass ratio")
plt.ylabel("Number of players")"Distribution of long-pass ratio (per player)")
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig("long_ratio_dist.png", dpi=150)

分桶统计(更直观的"分布")

bins = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
labels = [f"{bins[i]:.1f}-{bins[i+1]:.1f}" for i in range(len(bins)-1)]
player_stats["ratio_bucket"] = pd.cut(
    player_stats["long_ratio"], bins=bins, labels=labels,
    include_lowest=True, right=True
)
dist = player_stats["ratio_bucket"].value_counts().sort_index()
print(dist)
# 各桶占比
print((dist / dist.sum() * 100).round(1))

分位数(快速看分布形态)

print(player_stats["long_ratio"].describe(percentiles=[.1,.25,.5,.75,.9,.95]))

按传球距离的细粒度分布

# 每 5 米一个桶
df["dist_bucket"] = (df["pass_distance"] // 5 * 5).astype(int)
dist_by_range = df.groupby("dist_bucket").size()
print(dist_by_range)

SQL 脚本(PostgreSQL / MySQL 通用)

-- 假设表: passes(player_id, team_id, match_id, pass_distance)
-- 1) 按球员统计长短传比例
WITH agg AS (
  SELECT
    player_id,
    COUNT(*) AS total_passes,
    SUM(CASE WHEN pass_distance < 30 THEN 1 ELSE 0 END) AS short_passes,
    SUM(CASE WHEN pass_distance >= 30 THEN 1 ELSE 0 END) AS long_passes
  FROM passes
  GROUP BY player_id
)
SELECT
  player_id,
  total_passes,
  short_passes,
  long_passes,
  ROUND(short_passes::numeric / total_passes, 3) AS short_ratio,
  ROUND(long_passes::numeric / total_passes, 3)  AS long_ratio,
  ROUND(long_passes::numeric / NULLIF(short_passes,0), 3) AS long_short_ratio
FROM agg
ORDER BY long_ratio DESC;
-- 2) 比例分桶分布(每 0.1 一个桶)
WITH agg AS (
  SELECT
    player_id,
    COUNT(*) AS total,
    SUM(CASE WHEN pass_distance >= 30 THEN 1 ELSE 0 END)::numeric / COUNT(*) AS long_ratio
  FROM passes
  GROUP BY player_id
)
SELECT
  FLOOR(long_ratio * 10) / 10 AS ratio_bucket,
  COUNT(*) AS players
FROM agg
GROUP BY ratio_bucket
ORDER BY ratio_bucket;
-- 3) 按球队
SELECT
  team_id,
  COUNT(*) AS total,
  ROUND(AVG(CASE WHEN pass_distance < 30 THEN 1.0 ELSE 0 END), 3) AS short_ratio,
  ROUND(AVG(CASE WHEN pass_distance >= 30 THEN 1.0 ELSE 0 END), 3) AS long_ratio
FROM passes
GROUP BY team_id
ORDER BY long_ratio DESC;

Shell(awk)快速版

适合 CSV 快速抽样,字段顺序:player_id,team_id,match_id,pass_distance

#!/bin/bash
# 统计每个球员的长传/短传比例
awk -F',' 'NR>1 {
    total[$1]++;
    if ($4 < 30) short[$1]++;
    else          long[$1]++;
}
END {
    print "player_id,total,short,long,long_ratio";
    for (p in total) {
        lr = (total[p] ? long[p]/total[p] : 0);
        printf "%s,%d,%d,%d,%.3f\n", p, total[p], short[p], long[p]+0, lr;
    }
}' passes.csv | sort -t',' -k5 -nr

再把输出用 Python/R 画直方图即可。


结果解读建议

拿到分布后,重点看这几件事:

  1. 中位数:代表"典型球员"的长传比。
  2. P10 / P90:极端风格的边界(纯短传组织者 vs 长传清道夫)。
  3. 双峰?:若直方图出现两个峰,说明存在"两类球员",可进一步按位置(门将/中卫/中场/前锋)分组再看。
  4. 分位置对比:门将长传比通常 60%+,中场 10–20%,这是最重要的对照维度。

推荐加一段按位置分组代码:

# 若有 position 字段
print(df.groupby("position").apply(
    lambda g: (g["pass_distance"] >= 30).mean()
).sort_values(ascending=False))

注意事项

  • 阈值要固定:不同联赛/年龄段长传阈值可能不同(U12 用 20m 更合理)。
  • 排除特殊传球:角球、门球、界外球会影响比例,建议加 pass_type NOT IN ('corner','goal_kick','throw_in')。
  • 样本量过滤:总传球 < 20 的球员比例不稳定,建议过滤后再看分布。
  • 失败传球是否计入:统计"传球倾向"时通常计入,统计"成功率"时分开。

需要我针对特定数据源(Opta / StatsBomb / Wyscout / 自定义 CSV)给出字段映射版脚本,或加上按位置分组 + 显著性检验的完整分析流程吗?

抱歉,评论功能暂时关闭!

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝