python案例怎么看这波进攻的威胁程度?

wen python案例 11

本文目录导读:

python案例怎么看这波进攻的威胁程度?

  1. 第一步:核心数据准备
  2. 第二步:拆解威胁的四个维度(核心代码)
  3. 第三步:可视化威胁热力图(这才是“看”威胁的精髓)
  4. 第四步:动态威胁曲线(看时间段内的趋势)
  5. 总结:怎么“看”这波进攻的威胁程度?

这个问题问得很妙,因为“威胁程度”在足球分析里是一个模糊的、复合的概念,没有单一的魔法数字,但我们可以用 Python 把它拆解成几个可量化的子指标,然后融合成一个综合评分。

假设你已经有了球员的实时坐标数据(X, Y轴)和球的位置,以下是我基于数据科学视角,为你设计的 “三阶段威胁评估模型”,你可以直接抄代码或改造成自己的工具。

第一步:核心数据准备

我们首先模拟一组数据(假设是进攻方从左向右进攻,球门在 X=105 米处)。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 模拟数据:球员坐标 (x, y) 和 是否控球
# 假设:进攻方球员(红色) vs 防守方球员(蓝色)
attackers = np.array([
    [70, 30],  # 左边锋
    [75, 50],  # 中场核心(控球者)
    [85, 55],  # 中锋
    [80, 40],  # 前腰
    [60, 45]   # 后腰(策应)
])
defenders = np.array([
    [78, 52],  # 中卫1
    [82, 48],  # 中卫2
    [72, 60],  # 边后卫
    [65, 30],  # 边后卫
    [88, 50]   # 门将
])
ball_pos = attackers[1]  # 球在核心球员脚下

第二步:拆解威胁的四个维度(核心代码)

威胁程度 = 推进速度 + 射门威胁 + 传球穿透性 + 防守容错率

我们用 Python 计算这四个值:

def calculate_threat(ball_pos, attackers, defenders, goal_x=105):
    threat_scores = {}
    # 1. 推进威胁:离球门越近威胁越大(指数衰减或线性衰减)
    dist_to_goal = abs(ball_pos[0] - goal_x)
    progress_threat = max(0, 100 - dist_to_goal * 1.2)
    # 2. 射门角度威胁:计算持球人面对球门的夹角
    # 角度越正(接近90度),威胁越大
    if ball_pos[0] > 50:  # 进入进攻三区才计算
        dx = goal_x - ball_pos[0]
        dy = 0 - ball_pos[1]  # 球门中心在 (goal_x, 0)
        angle = abs(np.arctan2(dy, dx) * 180 / np.pi)
        # 修正:角度越接近0(越正对球门)威胁越大
        angle_threat = max(0, 90 - abs(angle)) * 0.8
    else:
        angle_threat = 0
    # 3. 穿越防线威胁:计算防守球员距离持球人的最短距离
    # 如果防守球员离得太近(<2米),威胁降低
    closest_def_dist = min(np.linalg.norm(def - ball_pos for def in defenders if def[0] > ball_pos[0] - 5))
    if closest_def_dist < 5:
        pressure_penalty = 30
    elif closest_def_dist < 10:
        pressure_penalty = 15
    else:
        pressure_penalty = 0
    pressure_threat = 100 - pressure_penalty
    # 4. 空间利用威胁:是否存在向前的空档(用传球角度衡量)
    # 计算队友中是否有在向前跑并能接球的角度
    vacant_space = 0
    for teammate in attackers:
        if teammate[0] > ball_pos[0]:  # 队友在球前面
            # 计算传球路线是否被防守遮挡(简化版:看中间有没有人)
            line_vector = teammate - ball_pos
            dist = np.linalg.norm(line_vector)
            if dist > 10:  # 长距离传球
                vacant_space += 20
    # 综合评分
    total = progress_threat + angle_threat + pressure_threat * 0.5 + vacant_space
    return total, progress_threat, angle_threat, pressure_threat, vacant_space
# 调用
score, prog, ang, press, space = calculate_threat(...)

第三步:可视化威胁热力图(这才是“看”威胁的精髓)

数据说了不算,画出来才直观,我们给整个球场做一个威胁网格:

def plot_threat_heatmap(attackers, defenders, ball_pos):
    x = np.linspace(0, 105, 50)  # 球场长
    y = np.linspace(0, 68, 40)   # 球场宽
    heatmap = np.zeros((len(y), len(x)))
    for i, xi in enumerate(x):
        for j, yj in enumerate(y):
            # 计算该点作为“潜在接球点”的威胁
            # 越深入禁区、离控球人越近且有空档,威胁越高
            dist_to_goal = abs(xi - 105)
            dist_to_ball = np.linalg.norm([xi - ball_pos[0], yj - ball_pos[1]])
            # 位置基础分
            base = max(0, 100 - dist_to_goal * 1.5)
            # 防守压制(如果附近有防守球员)
            def_penalty = 0
            for d in defenders:
                dist_d = np.linalg.norm([xi - d[0], yj - d[1]])
                if dist_d < 3:
                    def_penalty += 30
            # 传球可达性(离控球人越远,传球难度越大)
            passability = max(0, 100 - dist_to_ball * 2)
            heatmap[j, i] = base + passability * 0.5 - def_penalty
    # 画图
    plt.figure(figsize=(12, 6))
    plt.imshow(heatmap, extent=[0, 105, 0, 68], origin='lower', cmap='hot', alpha=0.7)
    plt.colorbar(label='威胁指数')
    # 标球员
    plt.scatter(attackers[:, 0], attackers[:, 1], c='red', marker='o', s=100, label='攻击方')
    plt.scatter(defenders[:, 0], defenders[:, 1], c='blue', marker='s', s=100, label='防守方')
    plt.scatter(ball_pos[0], ball_pos[1], c='white', marker='*', s=200, label='球')
    plt.text(105, 34, '球门', fontsize=12, ha='center')
    plt.legend()
    plt.title('实时进攻威胁热力图')
    plt.show()

第四步:动态威胁曲线(看时间段内的趋势)

如果你有 90 分钟的连续数据,更牛的做法是绘制“威胁时间轴”

# 假设你每秒钟计算一次威胁值
time_series = np.random.normal(50, 20, 90*60)  # 模拟数据
# 用滑动窗口找“爆发点”
def detect_high_threat(series, threshold=75, window=30):
    high_periods = []
    for i in range(len(series)-window):
        window_avg = np.mean(series[i:i+window])
        if window_avg > threshold:
            high_periods.append((i, window_avg))
    # 合并相邻的高威胁期
    merged = []
    for start, val in high_periods:
        if merged and start - merged[-1][0] < 60:
            merged[-1] = (merged[-1][0], max(val, merged[-1][1]))
        else:
            merged.append((start, val))
    return merged
# 输出:第 X 分钟到第 Y 分钟,威胁值高达 Z!

怎么“看”这波进攻的威胁程度?

最简单的判断标准(不用看代码):

  1. 如果持球人离球门 < 20 米且正对球门 -> 威胁极高(阿森纳的那种定位球)。
  2. 如果禁区内有 3 名以上队友没人盯防 -> 威胁爆表(拜仁的边中结合)。
  3. 如果传球路线全部被封锁且持球人背身 -> 威胁很低(钝刀切肉)。

用 Python 看,就是把以上直觉变成数字:

  • 威胁值 > 150:红区警报,大概率要丢球。
  • 威胁值 80~150:黄区,危险进攻。
  • 威胁值 < 80:绿区,可以稍微回撤。

如果你有具体的数据(CSV 文件里的一行行坐标),把数据丢进上面的函数里,输出一个 score 就行,需要我帮你针对某一种数据结构(StatsBomb 格式)写适配代码吗?

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