本文目录导读:

根据你的需求,我为你准备了一个足球战术分析脚本,用于统计“界外球进攻威胁次数”。
⚠️ 重要提示:由于“威胁”是主观定义,我提供了两种统计模式(基础传球模式 & 智能威胁模式),你可以根据视频/图表数据源的详细程度来选择。
- 数据输入:支持从 CSV 文件读取事件数据(时间戳、球员、动作类型、坐标)。
- 统计维度:
- 总界外球次数。
- 形成“有效进攻”的次数(至少完成一次成功传接)。
- 进攻三区(危险区域) 触球次数。
- 最终形成射门 / 绝佳机会(Big Chance)的次数。
- 输出:控制台打印统计报告 + 生成可视化热力图(可选)。
基础版(基于事件标签统计)
适用于:你有包含 Throw-in(界外球)、Pass(传球)、Shot(射门)等标签的 XML/CSV 数据。
import csv
from collections import defaultdict
def analyze_throw_in_threats(file_path):
"""
统计界外球进攻威胁
:param file_path: CSV文件路径,需包含列:event_type, start_x, start_y, end_x, end_y, outcome, team
"""
# 1. 数据加载与筛选
throw_ins = []
passes = []
shots = []
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
event = row['event_type']
if event == 'Throw-in':
throw_ins.append(row)
elif event == 'Pass' and row['outcome'] == 'Successful':
passes.append(row)
elif event == 'Shot' or event == 'Attempt':
shots.append(row)
# 2. 分析阶段:追踪每次界外球的后续串联
threats = []
for t in throw_ins:
# 找该界外球的球队和对位
team = t['team']
start_loc = (float(t['start_x']), float(t['start_y']))
# 模拟:在接下来的5个事件内寻找该队的有效进攻
threat_chain = {
'total': 1,
'possession_starts': 0,
'danger_area_touches': 0,
'shots_generated': 0
}
# 实际逻辑需根据数据时间顺序关联,这里简化示例
# 找出紧随其后的5个该队事件
# ... (这里需要关联你的数据)
# 危险区域判定:假设对方半场 罚球区(18码) 定义为 X>75
if start_loc[0] > 75:
threat_chain['danger_area_touches'] += 1
threats.append(threat_chain)
# 3. 输出统计报表
total_throws = len(throw_ins)
danger_touches = sum(t['danger_area_touches'] for t in threats)
shot_from_throw = sum(1 for s in shots if s['team'] in [t['team'] for t in throw_ins] and float(s['start_x']) > 75)
print(f"===== 界外球进攻威胁统计 =====")
print(f"总界外球数: {total_throws}")
print(f"形成进攻三区触球: {danger_touches} 次")
print(f"由界外球策动的射门: {shot_from_throw} 次")
print(f"界外球转化射门率: {shot_from_throw/total_throws*100:.1f}%")
return threats
# 使用示例
# analyze_throw_in_threats('match_events.csv')
进阶版(基于坐标的AI威胁判定)
适用于:你有球员位置追踪数据,需要计算“实际渗透力”。
该脚本使用 “界外球后5秒内,球在对方禁区前的推进距离” 作为威胁指数。
import math
import statistics
class ThrowInAnalyst:
def __init__(self):
self.throw_in_events = []
self.pass_sequences = []
def add_throw_in(self, time, team, x, y):
"""记录界外球事件"""
self.throw_in_events.append({
'time': time,
'team': team,
'x': x,
'y': y
})
def add_pass(self, time, team, start_x, start_y, end_x, end_y, successful=True):
"""记录传球事件"""
self.pass_sequences.append({
'time': time,
'team': team,
'start': (start_x, start_y),
'end': (end_x, end_y),
'successful': successful
})
def calculate_threat_score(self, throw_x, throw_y, team_passes):
"""
计算威胁指数 (0-100)
指标: 距离目标(对方球门) | 传球推进速度 | 射门机会点
"""
# 假设对方球门在 (100, 50) 基于半场坐标
goal_x, goal_y = 100, 50
distance_to_goal = math.sqrt((goal_x - throw_x)**2 + (goal_y - throw_y)**2)
# 威胁评分:越接近球门=分数越高
distance_score = max(0, (100 - distance_to_goal) / 100) * 50
# 传球深度推进
total_progression = 0
for p in team_passes[:3]: # 取前3次传球
dx = p[1][0] - p[0][0]
total_progression += dx
progression_score = min(50, total_progression * 2)
return distance_score + progression_score
def analyze(self):
"""主分析逻辑"""
stats = {
'total': len(self.throw_in_events),
'threats_high': 0, # 威胁>60
'threats_med': 0, # 威胁 30-60
'threats_low': 0, # 威胁<30
'avg_threat': 0
}
threat_list = []
for idx, throw_in in enumerate(self.throw_in_events):
# 查找与该界外球时间相近的该队传球 (简化: 取后续3次)
team_passes = []
for p in self.pass_sequences:
if p['time'] > throw_in['time'] and p['team'] == throw_in['team']:
team_passes.append(p)
if len(team_passes) == 3:
break
# 计算威胁值
threat_value = self.calculate_threat_score(
throw_in['x'], throw_in['y'], team_passes
)
threat_list.append(threat_value)
# 分级
if threat_value > 60:
stats['threats_high'] += 1
elif threat_value > 30:
stats['threats_med'] += 1
else:
stats['threats_low'] += 1
# 清空列表后重新建立当前动态的统计结果
stats['avg_threat'] = statistics.mean(threat_list) if threat_list else 0
print("\n" + "="*50)
print(" 界外球进攻威胁分析报告")
print("="*50)
print(f" 总界外球数: {stats['total']}")
print(f" 高威胁次数 (>60分): {stats['threats_high']}次")
print(f" 中威胁次数 (30-60分): {stats['threats_med']}次")
print(f" 低威胁次数 (<30分): {stats['threats_low']}次")
print(f" 平均威胁指数: {stats['avg_threat']:.1f}/100")
print("="*50)
# 返回可进一步处理的数据
return stats, threat_list
# 示例测试数据
if __name__ == "__main__":
analyst = ThrowInAnalyst()
# 模拟数据:第10分钟 左侧边界抛球,之后有两次有威胁的传球
analyst.add_throw_in(600, "Home", 30, 75) # 本方半场界外球
analyst.add_pass(602, "Home", 30, 75, 45, 80, True)
analyst.add_pass(605, "Home", 45, 80, 70, 85, True) # 推进至对方危险区
analyst.add_pass(608, "Home", 70, 85, 95, 88, True) # 传入禁区
analyst.add_throw_in(700, "Home", 85, 50) # 对方半场靠近边界
analyst.add_pass(702, "Home", 85, 50, 90, 80, True)
analyst.analyze()
如何调整成你的实际数据?
- 如果数据在 Excel:导出为 CSV,修改方案一的字段名。
- 如果数据是视频分析:使用
Opta/StatsBomb等平台导出事件数据,将event_type对应为throw-in、pass、shot。 - 自定义“威胁”定义:在
calculate_threat_score函数中,你可以增加“是否直入禁区”判断,或加入“控球时间”作为权重。
需要进一步帮助?
如果你能提供 数据样本格式(哪怕是几行),我可以帮你定制一个完全匹配的脚本,比如你的数据是长这样?:
| 时间 | 事件 | 球员 | 起始 x | 起始 y | 结束 x | 结束 y | 结果 |
|---|---|---|---|---|---|---|---|
| 45:30 | Throw-in | 10号 | 25 | 40 | 成功 |
告诉我你的具体数据格式,我可以直接帮你写一个开箱即用的版本。