综合Python案例,中场绞杀夺回球权对比?

wen python案例 1

本文目录导读:

综合Python案例,中场绞杀夺回球权对比?

  1. 项目目标
  2. 核心分析指标
  3. Python代码实现框架
  4. 实际案例对比(模拟数据示意)
  5. 高级拓展:使用追踪数据
  6. 总结建议

这是一个非常有趣的足球战术分析主题,在足球比赛中,“中场绞杀”通常指的是高位压迫中场区域围抢,其目的是在对方由守转攻的瞬间,通过多人在中场区域(特别是中圈附近)进行高强度的逼抢,迫使对方失误,从而夺回球权并直接形成反击。

要利用Python进行“中场绞杀夺回球权”的数据对比分析,通常需要事件数据追踪数据,以下是一个综合性的Python案例框架,假设你拥有类似StatsBomb、Wyscout或OPTA格式的数据。


项目目标

对比分析球队A球队B(或同一球队的两种战术阶段)在中场区域(中线前后各15-20米)通过“绞杀式压迫”夺回球权的效率、位置及后续威胁。

核心分析指标

  1. 中场夺回球权总数:在中场区域完成防守动作(抢断、拦截、解围、对方失误)的次数。
  2. 夺回球权后的“攻转守”时间:从夺回球权到完成第一次射门或关键传球的时间(秒)。
  3. 抢断成功率:中场区域抢断次数 / 中场区域抢断尝试次数。
  4. 压迫强度热力图:中场区域防守动作发生的空间密度。
  5. 后续威胁转化率:中场夺回球权后,形成射门或进球的百分比。

Python代码实现框架

环境准备与数据加载

假设数据格式为CSV,包含以下列:event_type, x, y, team_id, minute, second, possession_id, outcome

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.patches import Rectangle, Circle
import warnings
warnings.filterwarnings('ignore')
# 加载数据(示例)
def load_football_data(path='match_events.csv'):
    df = pd.read_csv(path)
    return df
df = load_football_data()

定义中场区域与“绞杀”事件识别

足球场规格假设为105m x 68m,中圈半径为9.15m,我们将“中场”定义为 x 坐标在 [30, 75] 区间(从本方底线到对方底线)。

# 定义中场区域(x坐标:中场线两侧各20米)
MIDFIELD_X_MIN = 30
MIDFIELD_X_MAX = 75
# 判断是否在中场
def is_in_midfield(x):
    return MIDFIELD_X_MIN <= x <= MIDFIELD_X_MAX
# 定义“绞杀”事件类型(抢断、拦截、犯规、对方失误)
PRESS_EVENTS = ['Tackle', 'Interception', 'Pressure', 'Ball Recovery', 'Error']
def is_press_event(row):
    return row['event_type'] in PRESS_EVENTS and is_in_midfield(row['x'])
# 标记夺回球权事件
df['is_midfield_regain'] = df.apply(is_press_event, axis=1)

团队对比统计

# 按球队分组统计中场夺回球权次数
team_stats = df[df['is_midfield_regain']].groupby('team_id').agg(
    total_regains=('event_id', 'count'),
    avg_x=('x', 'mean'),
    avg_y=('y', 'mean')
).reset_index()
print("中场绞杀夺回球权统计:")
print(team_stats)
# 计算成功率(抢断成功/抢断尝试)
tackle_stats = df[df['event_type'].isin(['Tackle', 'Pressure'])].groupby(['team_id', 'event_type']).agg(
    attempts=('event_id', 'count'),
    successes=('outcome', lambda x: (x == 'success').sum())
)
tackle_stats['success_rate'] = tackle_stats['successes'] / tackle_stats['attempts'] * 100
print(tackle_stats)

高级分析:夺回球权后的“威胁指数”

通过计算夺回球权后的秒数内是否发生射门或关键传球。

# 假设数据已按时间排序
df_sorted = df.sort_values(['match_id', 'minute', 'second'])
# 找出每一个中场夺回事件后5秒内的下一个事件
def calculate_threat(df_sorted):
    threats = []
    for idx, event in df_sorted[df_sorted['is_midfield_regain']].iterrows():
        # 找到该事件后5秒内的事件
        future = df_sorted[(df_sorted['minute']*60 + df_sorted['second'] > 
                           event['minute']*60 + event['second']) & 
                          (df_sorted['minute']*60 + df_sorted['second'] <= 
                           event['minute']*60 + event['second'] + 5) & 
                          (df_sorted['team_id'] == event['team_id'])]
        # 检查是否有射门或关键传球
        threat_event = future[future['event_type'].isin(['Shot', 'Key Pass'])]
        if not threat_event.empty:
            threats.append({
                'regain_event_id': event['event_id'],
                'threat_type': threat_event.iloc[0]['event_type'],
                'time_to_threat': (threat_event.iloc[0]['minute']*60 + threat_event.iloc[0]['second']) - 
                                  (event['minute']*60 + event['second']),
                'x_start': event['x'],
                'y_start': event['y']
            })
    return pd.DataFrame(threats)
threat_df = calculate_threat(df_sorted)
print(f"从中场绞杀中直接形成的威胁次数: {len(threat_df)}")
print(f"平均形成威胁时间: {threat_df['time_to_threat'].mean():.2f}秒")

可视化:中场热力图与对比

# 绘制两支球队的中场夺回球权热力图
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
team_ids = df['team_id'].unique()
for ax, team_id in zip(axes, team_ids):
    team_data = df[(df['team_id'] == team_id) & (df['is_midfield_regain'])]
    # 画球场背景
    ax.add_patch(Rectangle((0, 0), 105, 68, fill=False, edgecolor='black', linewidth=2))
    ax.plot([105/2, 105/2], [0, 68], color='black', linewidth=1.5)
    ax.add_patch(Circle((105/2, 34), 9.15, fill=False, edgecolor='black', linewidth=1.5))
    # 绘制热力图(使用核密度估计)
    from scipy.stats import gaussian_kde
    if len(team_data) > 1:
        kde = gaussian_kde([team_data['x'], team_data['y']])
        x_grid, y_grid = np.mgrid[30:75:100j, 0:68:100j]
        z = kde(np.vstack([x_grid.ravel(), y_grid.ravel()])).reshape(x_grid.shape)
        ax.contourf(x_grid, y_grid, z, levels=20, cmap='Reds', alpha=0.7)
        ax.scatter(team_data['x'], team_data['y'], alpha=0.6, s=30, c='white', edgecolors='black')
    ax.set_xlim(0, 105)
    ax.set_ylim(0, 68)
    ax.set_title(f'Team {team_id} - Midfield Regain Heatmap')
    ax.set_aspect('equal')
plt.tight_layout()
plt.show()

实际案例对比(模拟数据示意)

假设我们有两支球队:

指标 球队A(高位压迫型) 球队B(中场保守型)
中场夺回球权总数 47次 22次 A更激进
中场抢断成功率 68% 55% A效率更高
夺回后5秒内射门次数 8次 2次 A反击威胁更大
夺回球权平均x坐标 57m(更靠近对方) 42m(本方中场) 压迫线靠前
对手失误率 40% 25% A施加压力更大

Python输出可视化对比图表

# 雷达图对比
from math import pi
categories = ['Regains', 'Success Rate %', 'Shot Threats', 'Avg Pressure Line', 'Opponent Errors']
N = len(categories)
values_teamA = [47, 68, 8, 57, 40]
values_teamB = [22, 55, 2, 42, 25]
# 归一化到0-100
norm_A = [v/max(values_teamA + values_teamB)*100 for v in values_teamA]
norm_B = [v/max(values_teamA + values_teamB)*100 for v in values_teamB]
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
fig, ax = plt.subplots(figsize=(8,8), subplot_kw=dict(polar=True))
ax.plot(angles, norm_A + norm_A[:1], 'o-', linewidth=2, label='Team A (Pressing)')
ax.fill(angles, norm_A + norm_A[:1], alpha=0.25)
ax.plot(angles, norm_B + norm_B[:1], 's-', linewidth=2, label='Team B (Conservative)')
ax.fill(angles, norm_B + norm_B[:1], alpha=0.25)
ax.set_xticklabels(categories)
ax.legend(loc='upper right')'Midfield Press Performance: Team A vs Team B')
plt.show()

高级拓展:使用追踪数据

如果你拥有球员的追踪数据(如每秒位置),你可以:

  1. 定义“绞杀密度”:计算每个时间点,距离持球队员3米内的防守球员数量。
  2. 识别“绞杀时机”:当防守球员在对方半场连续3秒内超过3人时,标记为“绞杀期”。
  3. 对比:绞杀期内的夺回球权概率 vs 非绞杀期。
# 伪代码示意(假设有tracking_data)
def calculate_press_density(ball_position, player_positions, threshold=3):
    defenders_near = [p for p in player_positions 
                     if distance(p, ball_position) < 3]
    return len(defenders_near)
# 对每个时间窗口计算
tracking_df['press_density'] = tracking_df.apply(calculate_press_density, axis=1)
# 找出高密度时段(绞杀)
high_press_periods = tracking_df[tracking_df['press_density'] >= 3]

总结建议

这个综合Python案例能帮助你量化“中场绞杀”战术的实际效果,通过对比不同球队或不同战术时期的数据,你可以发现:

  • 高压迫是否导致更多的中场夺回球权?
  • 这些夺回球权是否真正转化为有威胁的进攻机会?
  • 有没有球队A的中场压迫成功率更高,但后续威胁转化率却不如球队B?(可能是因压迫后身体失衡、传球精度下降)

实际应用中,推荐使用 StatsBombRmplsoccer 进行更专业的足球数据可视化。

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