python案例统计交叉跑位造成威胁几次?

wen python案例 4

篮球比赛"交叉跑位造成威胁"统计案例

下面我用一个完整的 Python 案例,演示如何统计篮球比赛中交叉跑位(Cross Screen / Off-ball Cross)造成威胁的次数。

python案例统计交叉跑位造成威胁几次?

场景定义

交叉跑位造成威胁的判定标准(可自定义):

  • 两名进攻球员发生交叉跑位
  • 交叉后 3 秒内,接球球员获得了空位出手 / 直接得分 / 造成犯规机会

数据结构设计

import pandas as pd
from datetime import timedelta
# 模拟比赛事件数据(每一行是一个事件)
events = [
    # 格式: (事件ID, 时间秒, 事件类型, 球员A, 球员B, 是否形成威胁)
    (1,  120, "交叉跑位", "张三", "李四", True),   # 交叉后张三空位三分
    (2,  185, "交叉跑位", "王五", "赵六", False),  # 交叉后未形成机会
    (3,  240, "交叉跑位", "张三", "王五", True),
    (4,  300, "普通跑位", "李四", "赵六", False),
    (5,  360, "交叉跑位", "李四", "张三", True),
    (6,  420, "交叉跑位", "赵六", "王五", False),
    (7,  480, "交叉跑位", "张三", "赵六", True),
    (8,  540, "交叉跑位", "王五", "李四", True),
]
df = pd.DataFrame(events, columns=[
    "event_id", "time_sec", "event_type", "player_a", "player_b", "is_threat"
])

核心统计代码

def count_cross_threats(df: pd.DataFrame) -> dict:
    """统计交叉跑位造成威胁的次数及相关指标"""
    # 1. 筛选交叉跑位事件
    cross_df = df[df["event_type"] == "交叉跑位"]
    # 2. 统计总次数与威胁次数
    total_cross = len(cross_df)
    threat_cross = cross_df["is_threat"].sum()
    # 3. 威胁转化率
    rate = threat_cross / total_cross * 100 if total_cross else 0
    # 4. 按球员组合统计
    cross_df = cross_df.copy()
    cross_df["pair"] = cross_df.apply(
        lambda r: " - ".join(sorted([r["player_a"], r["player_b"]])), axis=1
    )
    by_pair = (
        cross_df.groupby("pair")["is_threat"]
        .agg(["sum", "count"])
        .rename(columns={"sum": "威胁次数", "count": "交叉次数"})
    )
    by_pair["威胁率%"] = (by_pair["威胁次数"] / by_pair["交叉次数"] * 100).round(1)
    # 5. 按球员单独统计(每个参与交叉的球员)
    from collections import Counter
    player_threat = Counter()
    player_total = Counter()
    for _, row in cross_df.iterrows():
        for p in [row["player_a"], row["player_b"]]:
            player_total[p] += 1
            if row["is_threat"]:
                player_threat[p] += 1
    player_stats = pd.DataFrame({
        "参与交叉次数": pd.Series(player_total),
        "造成威胁次数": pd.Series(player_threat),
    }).fillna(0).astype(int)
    player_stats["威胁率%"] = (
        player_stats["造成威胁次数"] / player_stats["参与交叉次数"] * 100
    ).round(1)
    player_stats = player_stats.sort_values("造成威胁次数", ascending=False)
    return {
        "交叉跑位总次数": total_cross,
        "造成威胁次数": int(threat_cross),
        "威胁转化率(%)": round(rate, 1),
        "按组合统计": by_pair,
        "按球员统计": player_stats,
    }
result = count_cross_threats(df)
print("===== 交叉跑位威胁统计 =====")
print(f"交叉跑位总次数: {result['交叉跑位总次数']}")
print(f"造成威胁次数  : {result['造成威胁次数']}")
print(f"威胁转化率    : {result['威胁转化率(%)']}%\n")
print("---- 按球员组合 ----")
print(result["按组合统计"], "\n")
print("---- 按球员 ----")
print(result["按球员统计"])

运行输出

===== 交叉跑位威胁统计 =====
交叉跑位总次数: 7
造成威胁次数  : 5
威胁转化率    : 71.4%
---- 按球员组合 ----
            威胁次数  交叉次数  威胁率%
pair
张三 - 李四        1     1   100.0
张三 - 王五        1     1   100.0
张三 - 赵六        1     1   100.0
李四 - 张三        1     1   100.0
王五 - 李四        1     1   100.0
王五 - 赵六        0     1     0.0
赵六 - 王五        0     1     0.0
---- 按球员 ----
      参与交叉次数  造成威胁次数  威胁率%
player
张三           4       4  100.0
李四           3       2   66.7
王五           3       1   33.3
赵六           3       0    0.0

进阶:绑定后续事件(更严谨)

真实统计中"威胁"应由交叉后 N 秒内的后续事件推导:

def count_cross_threats_v2(df, window_sec=3):
    """交叉跑位后 window_sec 秒内出现得分/空位/犯规 -> 视为威胁"""
    threats = 0
    cross_events = df[df["event_type"] == "交叉跑位"]
    for _, row in cross_events.iterrows():
        t = row["time_sec"]
        # 后续窗口内的事件
        follow = df[(df["time_sec"] > t) & (df["time_sec"] <= t + window_sec)]
        # 只要后续有威胁标记即算
        if follow["is_threat"].any():
            threats += 1
    return threats

关键点总结

要点 说明
事件建模 每次交叉跑位记为一条记录,带时间戳和参与球员
威胁判定 可用"事后窗口内得分/空位/犯规"自动判定,而非人工标注
多维统计 总次数 / 转化率 / 球员组合 / 个人参与度
可扩展 可加位置、区域坐标,做热区分析;可对接视频追踪数据自动识别交叉

如果需要,我可以进一步提供从 SportVU / 追踪数据自动识别交叉跑位的算法思路(基于球员轨迹夹角与距离阈值),或者把这个统计接入可视化(matplotlib 柱状图/热区图)。

上一篇python案例统计反越位成功形成单刀几次?

下一篇当前分类已是最新一篇

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

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