python案例统计界外球进攻威胁次数?

wen python案例 6

本文目录导读:

python案例统计界外球进攻威胁次数?

  1. 完整案例:界外球进攻威胁统计系统
  2. 可视化分析(可选)

我来设计一个足球比赛中统计界外球进攻威胁次数的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)

这个系统包含以下核心功能:

  1. 事件记录:完整记录每次界外球的详细信息
  2. 威胁评分:基于位置、战术和结果自动计算威胁分数
  3. 多维统计:按球队、球员、时间段进行统计分析
  4. 模式识别:自动识别危险进攻模式
  5. 报告生成:生成完整的分析报告

这个系统可以帮助教练和分析师:

  • 评估球队界外球进攻效率
  • 识别关键球员的威胁能力
  • 发现比赛中的进攻模式
  • 制定针对性的战术方案

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