本文目录导读:

我来设计一个足球比赛中统计界外球进攻威胁次数的Python案例。
完整案例:界外球进攻威胁统计系统
import pandas as pd
import numpy as np
from datetime import datetime
import json
class ThrowInThreatAnalyzer:
"""界外球进攻威胁分析器"""
def __init__(self):
# 威胁等级定义
self.threat_levels = {
'极低': 1,
'低': 2,
'中等': 3,
'高': 4,
'极高': 5
}
# 记录所有事件
self.events = []
def add_throw_in_event(self,
team_name,
player_name,
throw_in_position,
receiver_position,
is_long_throw,
is_direct_into_box,
outcome,
minute):
"""
添加一次界外球事件记录
参数:
- team_name: 球队名称
- player_name: 掷球员姓名
- throw_in_position: 掷球位置 (x, y坐标)
- receiver_position: 接球位置 (x, y坐标)
- is_long_throw: 是否为长距离界外球
- is_direct_into_box: 是否直接掷入禁区
- outcome: 结果 ('成功接球', '争抢', '直接射门', '解围', '出界', '犯规')
- minute: 比赛分钟
"""
event = {
'team': team_name,
'player': player_name,
'throw_in_position': throw_in_position,
'receiver_position': receiver_position,
'is_long_throw': is_long_throw,
'is_direct_into_box': is_direct_into_box,
'outcome': outcome,
'minute': minute,
'timestamp': datetime.now()
}
# 计算威胁分数
event['threat_score'] = self._calculate_threat_score(event)
self.events.append(event)
return event
def _calculate_distance_to_goal(self, position, goal_position=(105, 37.5)):
"""计算到球门的距离"""
return np.sqrt((position[0] - goal_position[0])**2 +
(position[1] - goal_position[1])**2)
def _calculate_threat_score(self, event):
"""
计算威胁分数 (1-10分)
考虑因素:
- 掷球位置距离球门的距离
- 接球位置离球门的距离
- 是否为长距离界外球
- 是否直接掷入禁区
- 结果类型
"""
score = 0
# 1. 掷球位置因素 (占总分30%)
throw_in_distance = self._calculate_distance_to_goal(event['throw_in_position'])
if throw_in_distance < 20:
score += 3 # 距离球门很近
elif throw_in_distance < 30:
score += 2 # 靠近禁区
elif throw_in_distance < 40:
score += 1 # 中场附近
# 超过40米不加分
# 2. 接球位置因素 (占总分30%)
receiver_distance = self._calculate_distance_to_goal(event['receiver_position'])
if receiver_distance < 15:
score += 3 # 直接在禁区/小禁区
elif receiver_distance < 25:
score += 2 # 禁区附近
elif receiver_distance < 35:
score += 1 # 大禁区外
# 3. 战术因素 (占总分20%)
if event['is_long_throw']:
score += 1
if event['is_direct_into_box']:
score += 1
# 4. 事件结果因素 (占总分20%)
outcome_scores = {
'直接射门': 2,
'成功接球': 1.5,
'争抢': 1,
'解围': 0.5,
'出界': 0,
'犯规': 0
}
score += outcome_scores.get(event['outcome'], 0)
# 标准化到1-10分
score = min(max(score, 1), 10)
return round(score, 1)
def get_team_threat_summary(self, team_name=None):
"""获取球队威胁统计"""
if team_name:
team_events = [e for e in self.events if e['team'] == team_name]
else:
team_events = self.events
if not team_events:
return {}
summary = {
'total_throw_ins': len(team_events),
'average_threat_score': np.mean([e['threat_score'] for e in team_events]),
'high_threat_count': len([e for e in team_events if e['threat_score'] >= 7]),
'medium_threat_count': len([e for e in team_events if 4 <= e['threat_score'] < 7]),
'low_threat_count': len([e for e in team_events if e['threat_score'] < 4]),
'long_throw_count': len([e for e in team_events if e['is_long_throw']]),
'into_box_count': len([e for e in team_events if e['is_direct_into_box']]),
'dangerous_zone_minutes': [e['minute'] for e in team_events if e['threat_score'] >= 8]
}
return summary
def get_threat_trend_by_minute(self, interval=15):
"""按时间段统计威胁趋势"""
trend = {}
for event in self.events:
period = f"{((event['minute']-1)//interval)*interval + 1}-{((event['minute']-1)//interval)*interval + interval}分钟"
if period not in trend:
trend[period] = {'count': 0, 'total_threat': 0}
trend[period]['count'] += 1
trend[period]['total_threat'] += event['threat_score']
# 计算平均威胁
for period in trend:
trend[period]['average_threat'] = trend[period]['total_threat'] / trend[period]['count']
return trend
def get_player_ranking(self):
"""球员威胁排名"""
player_stats = {}
for event in self.events:
player = event['player']
if player not in player_stats:
player_stats[player] = {
'throw_ins': 0,
'total_threat': 0,
'max_threat': 0,
'high_threat_throws': 0
}
player_stats[player]['throw_ins'] += 1
player_stats[player]['total_threat'] += event['threat_score']
player_stats[player]['max_threat'] = max(player_stats[player]['max_threat'],
event['threat_score'])
if event['threat_score'] >= 7:
player_stats[player]['high_threat_throws'] += 1
# 计算平均威胁并排序
for player in player_stats:
player_stats[player]['average_threat'] = (
player_stats[player]['total_threat'] / player_stats[player]['throw_ins']
)
ranking = sorted(player_stats.items(),
key=lambda x: (x[1]['average_threat'], x[1]['high_threat_throws']),
reverse=True)
return ranking
def identify_dangerous_patterns(self):
"""识别危险模式"""
patterns = []
# 模式1: 连续高威胁界外球
for i in range(len(self.events) - 2):
consecutive = self.events[i:i+3]
if all(e['threat_score'] >= 7 for e in consecutive):
patterns.append({
'type': '连续高威胁界外球',
'team': consecutive[0]['team'],
'minutes': [e['minute'] for e in consecutive],
'total_threat': sum(e['threat_score'] for e in consecutive)
})
# 模式2: 比赛末段界外球比例
late_events = [e for e in self.events if e['minute'] > 75]
if late_events and len(late_events) > len(self.events) * 0.3:
patterns.append({
'type': '比赛末段界外球比例过高',
'late_events_count': len(late_events),
'percentage': len(late_events) / len(self.events) * 100
})
# 模式3: 同一区域多次掷球
from collections import Counter
positions = Counter((round(e['throw_in_position'][0], 1),
round(e['throw_in_position'][1], 1))
for e in self.events)
hot_zones = {pos: count for pos, count in positions.items() if count >= 3}
if hot_zones:
patterns.append({
'type': '热点区域',
'hot_zones': hot_zones
})
return patterns
def generate_report(self):
"""生成完整分析报告"""
report = {
'总界外球次数': len(self.events),
'各队威胁统计': {},
'总体威胁分布': {},
'最危险球员': None,
'危险模式': self.identify_dangerous_patterns()
}
# 球队统计
for team in set(e['team'] for e in self.events):
report['各队威胁统计'][team] = self.get_team_threat_summary(team)
# 威胁分数分布
threat_scores = [e['threat_score'] for e in self.events]
report['总体威胁分布'] = {
'平均威胁': np.mean(threat_scores),
'最高威胁': max(threat_scores),
'最低威胁': min(threat_scores),
'高威胁次数': len([s for s in threat_scores if s >= 7]),
'中等威胁次数': len([s for s in threat_scores if 4 <= s < 7]),
'低威胁次数': len([s for s in threat_scores if s < 4])
}
# 最危险球员
ranking = self.get_player_ranking()
if ranking:
report['最危险球员'] = ranking[0][0]
return report
# 使用示例
def main():
# 初始化分析器
analyzer = ThrowInThreatAnalyzer()
# 模拟一场比赛数据
sample_events = [
# (球队, 球员, 掷球位置, 接球位置, 长掷, 掷入禁区, 结果, 分钟)
("曼联", "卢克·肖", (38, 35), (50, 30), False, False, "成功接球", 5),
("曼联", "卢克·肖", (25, 32), (42, 38), False, True, "争抢", 12),
("利物浦", "罗伯逊", (30, 40), (48, 35), True, True, "直接射门", 15),
("曼联", "马拉西亚", (35, 36), (52, 32), True, False, "成功接球", 20),
("利物浦", "罗伯逊", (20, 38), (35, 42), True, True, "争抢", 25),
("曼联", "卢克·肖", (32, 33), (46, 28), False, True, "解围", 32),
("利物浦", "阿诺德", (15, 35), (28, 40), False, False, "成功接球", 45),
("曼联", "马拉西亚", (28, 30), (44, 36), True, True, "直接射门", 60),
("利物浦", "罗伯逊", (36, 42), (50, 38), False, False, "成功接球", 68),
("利物浦", "罗伯逊", (31, 35), (45, 33), True, True, "争抢", 72),
("曼联", "卢克·肖", (26, 34), (40, 30), False, True, "直接射门", 78),
("利物浦", "阿诺德", (40, 37), (52, 32), False, False, "出界", 82),
("曼联", "马拉西亚", (24, 31), (38, 35), True, True, "争抢", 85),
("利物浦", "罗伯逊", (18, 33), (32, 38), True, True, "直接射门", 88),
("曼联", "卢克·肖", (30, 36), (43, 34), False, True, "成功接球", 90)
]
for event_data in sample_events:
analyzer.add_throw_in_event(
team_name=event_data[0],
player_name=event_data[1],
throw_in_position=event_data[2],
receiver_position=event_data[3],
is_long_throw=event_data[4],
is_direct_into_box=event_data[5],
outcome=event_data[6],
minute=event_data[7]
)
# 生成分析报告
report = analyzer.generate_report()
print("=" * 60)
print("界外球进攻威胁分析报告")
print("=" * 60)
print(f"\n1. 总览")
print(f" - 总界外球次数: {report['总界外球次数']}")
print(f" - 平均威胁分数: {report['总体威胁分布']['平均威胁']:.2f}")
print(f" - 最高威胁: {report['总体威胁分布']['最高威胁']}")
print(f"\n2. 各队威胁统计")
for team, stats in report['各队威胁统计'].items():
print(f" {team}:")
print(f" - 界外球次数: {stats['total_throw_ins']}")
print(f" - 平均威胁: {stats['average_threat_score']:.2f}")
print(f" - 高威胁次数 ({stats['high_threat_count']}次)")
print(f" - 长掷球次数: {stats['long_throw_count']}")
print(f" - 掷入禁区次数: {stats['into_box_count']}")
if stats['dangerous_zone_minutes']:
print(f" - 危险时段: {stats['dangerous_zone_minutes']}")
print(f"\n3. 最危险球员: {report['最危险球员']}")
print(f"\n4. 球员威胁排名")
ranking = analyzer.get_player_ranking()
for i, (player, stats) in enumerate(ranking[:5], 1):
print(f" {i}. {player}: 平均威胁 {stats['average_threat_score']:.2f}, "
f"高威胁次数 {stats['high_threat_throws']}")
print(f"\n5. 危险模式识别")
for pattern in report['危险模式']:
print(f" - {pattern['type']}: {pattern}")
print(f"\n6. 威胁时间段分布")
trend = analyzer.get_threat_trend_by_minute()
for period, stats in trend.items():
print(f" {period}: {stats['count']}次, 平均威胁 {stats['average_threat']:.2f}")
# 输出JSON格式总结
print("\n" + "=" * 60)
print("关键指标摘要")
summary = {
'总进攻威胁': sum(e['threat_score'] for e in analyzer.events),
'球队威胁对比': {
team: stats['average_threat_score']
for team, stats in report['各队威胁统计'].items()
},
'进攻效率': report['总体威胁分布']['高威胁次数'] / report['总界外球次数']
}
print(json.dumps(summary, indent=2, ensure_ascii=False))
if __name__ == "__main__":
main()
可视化分析(可选)
import matplotlib.pyplot as plt
import seaborn as sns
def visualize_threat_analysis(analyzer):
"""可视化威胁分析结果"""
# 1. 威胁分数时间线
plt.figure(figsize=(12, 6))
minutes = [e['minute'] for e in analyzer.events]
scores = [e['threat_score'] for e in analyzer.events]
plt.subplot(2, 2, 1)
plt.plot(minutes, scores, 'o-')
plt.xlabel('比赛分钟')
plt.ylabel('威胁分数')
plt.title('界外球威胁时间线')
plt.grid(True, alpha=0.3)
# 2. 球队对比
teams = set(e['team'] for e in analyzer.events)
team_scores = {team: [] for team in teams}
for event in analyzer.events:
team_scores[event['team']].append(event['threat_score'])
plt.subplot(2, 2, 2)
data = [team_scores[team] for team in teams]
plt.boxplot(data, labels=list(teams))
plt.ylabel('威胁分数')
plt.title('球队威胁分数分布')
# 3. 时间段热力图
trend = analyzer.get_threat_trend_by_minute(10)
periods = list(trend.keys())
avg_threats = [trend[p]['average_threat'] for p in periods]
plt.subplot(2, 2, 3)
plt.bar(periods, avg_threats, color='skyblue')
plt.xlabel('时间段')
plt.ylabel('平均威胁')
plt.title('不同时间段平均威胁')
plt.xticks(rotation=45)
# 4. 位置热力图
plt.subplot(2, 2, 4)
positions = [(e['throw_in_position'][0], e['throw_in_position'][1])
for e in analyzer.events]
x = [p[0] for p in positions]
y = [p[1] for p in positions]
scores = [e['threat_score'] for e in analyzer.events]
scatter = plt.scatter(x, y, c=scores, cmap='RdYlGn', s=100, alpha=0.6)
plt.colorbar(scatter, label='威胁分数')
plt.xlabel('场地横向位置')
plt.ylabel('场地纵向位置')
plt.title('掷球位置与威胁关系')
plt.tight_layout()
plt.show()
# 使用可视化
# visualize_threat_analysis(analyzer)
这个系统包含以下核心功能:
- 事件记录:完整记录每次界外球的详细信息
- 威胁评分:基于位置、战术和结果自动计算威胁分数
- 多维统计:按球队、球员、时间段进行统计分析
- 模式识别:自动识别危险进攻模式
- 报告生成:生成完整的分析报告
这个系统可以帮助教练和分析师:
- 评估球队界外球进攻效率
- 识别关键球员的威胁能力
- 发现比赛中的进攻模式
- 制定针对性的战术方案