本文目录导读:

我来为您设计一个足球比赛中统计界外球进攻威胁次数的Python案例。
整体思路
界外球进攻威胁的判定需要考虑多个因素:
- 界外球位置(越靠近对方禁区威胁越大)
- 是否形成射门
- 是否形成传中
- 是否造成对方防守混乱
完整代码实现
import pandas as pd
import numpy as np
from datetime import datetime
import json
class ThrowInThreatAnalyzer:
"""界外球进攻威胁分析器"""
def __init__(self):
# 定义球场区域(将球场分为多个区域)
self.pitch_zones = {
'own_defensive': {'name': '本方后场', 'x_range': (0, 30), 'threat_weight': 0.1},
'own_midfield': {'name': '本方中场', 'x_range': (30, 50), 'threat_weight': 0.2},
'midfield': {'name': '中场', 'x_range': (50, 70), 'threat_weight': 0.3},
'opp_midfield': {'name': '对方中场', 'x_range': (70, 90), 'threat_weight': 0.5},
'opp_final_third': {'name': '对方前场', 'x_range': (90, 105), 'threat_weight': 0.8},
'opp_box': {'name': '对方禁区', 'x_range': (105, 120), 'threat_weight': 1.0}
}
# 结果存储
self.results = []
def judge_zone(self, x_coordinate):
"""判断界外球所在区域"""
for zone_id, zone_info in self.pitch_zones.items():
if zone_info['x_range'][0] <= x_coordinate < zone_info['x_range'][1]:
return zone_id, zone_info
return 'unknown', None
def analyze_throw_in(self, throw_in_data):
"""
分析单个界外球事件
参数:
throw_in_data: dict - 界外球数据
- position_x: 界外球位置的x坐标(0-120米)
- position_y: 界外球位置的y坐标(0-80米)
- player_position: 掷球后接球球员位置
- outcome: 掷球结果 ('射门', '助攻', '传中', '角球', '无效', '丢失')
- time: 比赛时间
返回:
dict - 分析结果
"""
try:
x_coord = throw_in_data.get('position_x', 0)
y_coord = throw_in_data.get('position_y', 40)
# 判断区域
zone_id, zone_info = self.judge_zone(x_coord)
# 基础威胁得分
base_threat = zone_info['threat_weight'] if zone_info else 0.3
# 根据结果加权
threat_score = base_threat
# 分析掷球结果
outcome = throw_in_data.get('outcome', '丢失')
outcome_multipliers = {
'射门': 2.0,
'助攻': 1.8,
'传中': 1.5,
'角球': 1.3,
'进球': 3.0,
'无效': 0.3,
'丢失': 0.1
}
threat_multiplier = outcome_multipliers.get(outcome, 0.5)
threat_score *= threat_multiplier
# 考虑接球位置(如果靠近球门)
if throw_in_data.get('player_position'):
player_x = throw_in_data['player_position'].get('x', 0)
# 接球位置越靠近对方球门,威胁越大
if player_x > 90:
threat_score *= 1.3
# 判断威胁等级
if threat_score >= 1.5:
threat_level = '高威胁'
elif threat_score >= 0.8:
threat_level = '中等威胁'
elif threat_score >= 0.3:
threat_level = '低威胁'
else:
threat_level = '无威胁'
# 记录分析结果
result = {
'time': throw_in_data.get('time', ''),
'position': (x_coord, y_coord),
'zone': zone_info['name'] if zone_info else '未知',
'outcome': outcome,
'base_threat': round(base_threat, 2),
'threat_score': round(threat_score, 2),
'threat_level': threat_level
}
self.results.append(result)
return result
except Exception as e:
print(f"分析界外球时出错: {e}")
return None
def analyze_batch(self, throw_in_events):
"""批量分析多个界外球事件"""
results = []
for event in throw_in_events:
result = self.analyze_throw_in(event)
if result:
results.append(result)
return results
def calculate_total_threats(self, high_threat_only=False):
"""计算总威胁次数"""
if not self.results:
return 0
if high_threat_only:
# 只计算高威胁
return sum(1 for r in self.results if r['threat_level'] == '高威胁')
else:
# 计算所有有威胁的界外球事件
return sum(1 for r in self.results if r['threat_level'] != '无威胁')
def print_analysis_report(self):
"""打印分析报告"""
print("=" * 60)
print("界外球进攻威胁分析报告")
print("=" * 60)
if not self.results:
print("暂无界外球数据分析")
return
# 统计数据
total_throw_ins = len(self.results)
high_threats = sum(1 for r in self.results if r['threat_level'] == '高威胁')
mid_threats = sum(1 for r in self.results if r['threat_level'] == '中等威胁')
low_threats = sum(1 for r in self.results if r['threat_level'] == '低威胁')
no_threats = total_throw_ins - high_threats - mid_threats - low_threats
print(f"\n总界外球次数: {total_throw_ins}")
print(f"高威胁次数: {high_threats}")
print(f"中等威胁次数: {mid_threats}")
print(f"低威胁次数: {low_threats}")
print(f"无威胁次数: {no_threats}")
print(f"\n进攻威胁总次数: {self.calculate_total_threats()}")
print(f"高威胁占比: {high_threats/total_throw_ins*100:.1f}%" if total_throw_ins > 0 else "")
# 按区域和结果分析
print("\n--- 区域分布 ---")
zone_stats = {}
for r in self.results:
zone = r['zone']
if zone not in zone_stats:
zone_stats[zone] = {'count': 0, 'threats': 0}
zone_stats[zone]['count'] += 1
if r['threat_level'] != '无威胁':
zone_stats[zone]['threats'] += 1
for zone, stats in zone_stats.items():
print(f"{zone}: 共{stats['count']}次, stats['threats']}次构成威胁")
# 详细结果列表
print("\n--- 详细事件列表 ---")
for idx, r in enumerate(self.results, 1):
print(f"{idx}. 时间: {r['time']}")
print(f" 位置: {r['position']}")
print(f" 区域: {r['zone']}")
print(f" 结果: {r['outcome']}")
print(f" 威胁得分: {r['threat_score']}")
print(f" 威胁等级: {r['threat_level']}")
print()
def generate_sample_data():
"""生成示例数据"""
return [
{
'time': '12:30',
'position_x': 110,
'position_y': 65,
'player_position': {'x': 108, 'y': 70},
'outcome': '射门',
'team': '主队'
},
{
'time': '25:10',
'position_x': 85,
'position_y': 35,
'player_position': {'x': 88, 'y': 40},
'outcome': '传中',
'team': '主队'
},
{
'time': '38:45',
'position_x': 60,
'position_y': 45,
'player_position': {'x': 62, 'y': 50},
'outcome': '丢失',
'team': '主队'
},
{
'time': '52:20',
'position_x': 115,
'position_y': 50,
'player_position': {'x': 112, 'y': 55},
'outcome': '助攻',
'team': '主队'
},
{
'time': '70:15',
'position_x': 95,
'position_y': 30,
'player_position': {'x': 97, 'y': 35},
'outcome': '角球',
'team': '主队'
},
{
'time': '83:50',
'position_x': 100,
'position_y': 20,
'player_position': {'x': 102, 'y': 25},
'outcome': '传中',
'team': '主队'
},
{
'time': '88:33',
'position_x': 30,
'position_y': 60,
'player_position': {'x': 35, 'y': 55},
'outcome': '丢失',
'team': '主队'
}
]
def main():
"""主函数示例"""
# 创建分析器
analyzer = ThrowInThreatAnalyzer()
# 生成示例数据
sample_events = generate_sample_data()
# 分析界外球事件
print("开始分析界外球事件...")
results = analyzer.analyze_batch(sample_events)
# 打印分析报告
analyzer.print_analysis_report()
# 导出结果到JSON
with open('throw_in_analysis.json', 'w', encoding='utf-8') as f:
json.dump(analyzer.results, f, ensure_ascii=False, indent=2)
print("分析结果已保存到 throw_in_analysis.json")
# 额外分析示例
print("\n" + "="*60)
print("进阶统计数据")
print("="*60)
print(f"总界外球威胁次数: {analyzer.calculate_total_threats()}")
print(f"仅高威胁次数: {analyzer.calculate_total_threats(high_threat_only=True)}")
if __name__ == "__main__":
main()
简化版本(适合快速使用)
def simple_throw_in_threat_analysis(throw_in_data):
"""
简化的界外球威胁分析函数
参数:
throw_in_data: list of dict, 每个dict包含:
- x_position: 球在纵轴的位置(0-120)
- was_shot: 是否形成射门
- was_cross: 是否形成传中
- was_foul_won: 是否赢得犯规
返回:
tuple: (总次数, 威胁次数)
"""
threat_count = 0
total_count = len(throw_in_data)
for event in throw_in_data:
# 简单评分系统
threat_score = 0
# 位置因素 (x > 90 表示在对方30米区域)
if event['x_position'] > 90:
threat_score += 1
# 结果因素
if event.get('was_shot'):
threat_score += 2
if event.get('was_cross'):
threat_score += 1.5
if event.get('was_foul_won'):
threat_score += 0.5
# 判断是否构成威胁
if threat_score >= 1.5: # 至少要有位置优势加一个积极结果
threat_count += 1
return total_count, threat_count
# 使用示例
sample_data = [
{'x_position': 115, 'was_shot': True, 'was_cross': False, 'was_foul_won': False},
{'x_position': 85, 'was_shot': False, 'was_cross': True, 'was_foul_won': True},
{'x_position': 60, 'was_shot': False, 'was_cross': False, 'was_foul_won': False},
]
total, threats = simple_throw_in_threat_analysis(sample_data)
print(f"总界外球数: {total}, 威胁次数: {threats}")
使用说明
数据准备
需要准备界外球事件的数据,包含:
- 位置信息: 界外球发生的x坐标(模拟足球场长度0-120米)
- 结果: 掷球后发生了什么(射门、传中、助攻等)
- 时间: 事件发生时间
运行方式
python throw_in_analyzer.py
输出结果
程序会输出:
- 各种威胁等级的数量
- 总威胁次数
- 高威胁占比
- 按区域统计
- 每个事件的详细分析
- 自动保存JSON文件
判定标准说明
威胁等级判定:
- 高威胁(得分>=1.5): 在对方禁区附近获得球权并形成射门/助攻
- 中等威胁(得分>=0.8): 前场30米内的界外球形成传中或得到角球
- 低威胁(得分>=0.3): 中场的界外球有进攻的意图
- 无威胁: 防守压力下的求生性掷球
这个系统可以应用于:
- 赛后技术统计
- 球员/教练战术分析
- 视频分析师的数据标注
- 球员专项训练效果评估
您可以根据实际需求调整权重参数和判定标准!