综合python案例,国家队比赛日后遗症存在?

wen python案例 2

我来设计一个综合Python案例,分析足球"国家队比赛日后遗症"现象(即国家队比赛后,俱乐部球员表现下滑的现象)。

综合python案例,国家队比赛日后遗症存在?

项目:足球"FIFA病毒"效应分析系统

数据模拟模块

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
from scipy import stats
import warnings
warnings.filterwarnings('ignore')
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
class FootbalDataGenerator:
    """足球数据模拟生成器"""
    def __init__(self, seed=42):
        np.random.seed(seed)
        self.teams = ['曼联', '曼城', '利物浦', '切尔西', '阿森纳', '热刺']
        self.players = {}
        self._generate_players()
    def _generate_players(self):
        """生成球员基础数据"""
        player_count = 0
        for team in self.teams:
            for i in range(15):  # 每队15名核心球员
                self.players[player_count] = {
                    'name': f'{team}_球员{i+1}',
                    'team': team,
                    'position': np.random.choice(['前锋', '中场', '后卫', '门将']),
                    'base_rating': np.random.normal(75, 5),  # 基础能力值
                    'injury_prone': np.random.uniform(0.1, 0.5),  # 伤病倾向
                }
                player_count += 1
    def generate_match_data(self, player_id, date, is_national_match=False):
        """生成单场比赛数据"""
        player = self.players[player_id]
        # 基础表现评分
        base_score = player['base_rating'] + np.random.normal(0, 3)
        # 如果是国家队比赛,评分会有额外波动
        if is_national_match:
            base_score += np.random.normal(1, 2)  # 国家队比赛表现
        # 伤病影响
        if np.random.random() < player['injury_prone'] * 0.3:
            base_score -= np.random.uniform(5, 15)  # 伤病导致表现下降
        return {
            'date': date,
            'player_id': player_id,
            'is_national': is_national_match,
            'rating': max(0, min(100, base_score)),  # 限制在0-100
            'minutes_played': np.random.choice([60, 75, 80, 90, 90, 90]),
            'goals': np.random.poisson(0.3),
            'assists': np.random.poisson(0.2),
        }

数据分析和统计检验模块

class FifaVirusAnalyzer:
    """FIFA病毒效应分析器"""
    def __init__(self, data_generator):
        self.data_generator = data_generator
        self.df = None
        self.results = {}
    def generate_season_data(self, season_days=180):
        """生成一个赛季的数据"""
        all_data = []
        start_date = datetime(2023, 8, 1)
        # 定义国家队比赛日(模拟)
        national_dates = [
            start_date + timedelta(days=45),
            start_date + timedelta(days=90),
            start_date + timedelta(days=135),
        ]
        for player_id in self.data_generator.players:
            for day in range(season_days):
                date = start_date + timedelta(days=day)
                # 每周2场比赛
                if day % 3 == 0:
                    is_national = date in national_dates or \
                                 any(abs((date - nd).days) <= 2 for nd in national_dates)
                    match_data = self.data_generator.generate_match_data(
                        player_id, 
                        date,
                        is_national
                    )
                    all_data.append(match_data)
        self.df = pd.DataFrame(all_data)
        return self.df
    def analyze_fifa_virus(self):
        """分析FIFA病毒效应"""
        if self.df is None:
            raise ValueError("请先生成数据")
        # 添加国家队比赛后时间特征
        df = self.df.copy()
        # 识别国家队比赛日后第1-5场比赛
        national_dates = df[df['is_national']]['date'].unique()
        # 为每场比赛计算与最近国家队比赛日的距离
        df['days_since_national'] = df['date'].apply(
            lambda x: min([abs((x - nd).days) for nd in national_dates])
            if len(national_dates) > 0 else 999
        )
        # 定义受影响区间(比赛后0-14天)
        df['affected'] = df['days_since_national'].apply(
            lambda x: x <= 14 and x >= 0
        )
        # 分组统计
        affected_stats = df[df['affected']]['rating'].describe()
        normal_stats = df[~df['affected']]['rating'].describe()
        # 执行独立样本t检验
        t_stat, p_value = stats.ttest_ind(
            df[df['affected']]['rating'],
            df[~df['affected']]['rating']
        )
        # 计算效应量
        n1 = len(df[df['affected']])
        n2 = len(df[~df['affected']])
        s1 = df[df['affected']]['rating'].var()
        s2 = df[~df['affected']]['rating'].var()
        # Cohen's d
        pooled_std = np.sqrt(((n1-1)*s1 + (n2-1)*s2) / (n1+n2-2))
        cohens_d = (df[df['affected']]['rating'].mean() - 
                   df[~df['affected']]['rating'].mean()) / pooled_std
        self.results = {
            'affected_period': {
                'mean': affected_stats['mean'],
                'std': affected_stats['std'],
                'count': affected_stats['count'],
                'sample': df[df['affected']]['rating'].values
            },
            'normal_period': {
                'mean': normal_stats['mean'],
                'std': normal_stats['std'],
                'count': normal_stats['count'],
                'sample': df[~df['affected']]['rating'].values
            },
            't_test': {
                't_statistic': t_stat,
                'p_value': p_value,
                'significant': p_value < 0.05
            },
            'effect_size': cohens_d
        }
        return self.results
    def analyze_team_impact(self):
        """分析各球队受影响程度"""
        df = self.df.copy()
        # 关联球员所属球队
        player_team_map = {
            pid: info['team'] 
            for pid, info in self.data_generator.players.items()
        }
        df['team'] = df['player_id'].map(player_team_map)
        # 识别国家队比赛日期
        national_dates = df[df['is_national']]['date'].unique()
        # 计算每场比赛与国家队比赛的距离
        df['days_since_national'] = df['date'].apply(
            lambda x: min([abs((x - nd).days) for nd in national_dates])
        )
        df['affected'] = df['days_since_national'] <= 14
        # 各球队受影响程度
        team_impact = []
        for team in self.data_generator.teams:
            team_df = df[df['team'] == team]
            affected = team_df[team_df['affected']]['rating']
            normal = team_df[~team_df['affected']]['rating']
            if len(affected) > 0 and len(normal) > 0:
                impact = {
                    'team': team,
                    'normal_mean': normal.mean(),
                    'affected_mean': affected.mean(),
                    'decline': normal.mean() - affected.mean(),
                    'decline_pct': (normal.mean() - affected.mean()) / normal.mean() * 100,
                    'player_count': len(team_df),
                }
                team_impact.append(impact)
        return pd.DataFrame(team_impact)

可视化模块

class FifaVirusVisualizer:
    """FIFA病毒效应可视化"""
    def __init__(self, results, analyzer):
        self.results = results
        self.analyzer = analyzer
    def plot_rating_distribution(self):
        """绘制评分分布对比图"""
        fig, axes = plt.subplots(1, 2, figsize=(12, 5))
        # 受影响 vs 正常评分分布
        affected_data = self.results['affected_period']['sample']
        normal_data = self.results['normal_period']['sample']
        # 直方图
        axes[0].hist(affected_data, alpha=0.5, label='国家队比赛后', bins=30)
        axes[0].hist(normal_data, alpha=0.5, label='正常时期', bins=30)
        axes[0].set_xlabel('球员评分')
        axes[0].set_ylabel('频数')
        axes[0].set_title('评分分布对比')
        axes[0].legend()
        # 小提琴图
        data = [affected_data, normal_data]
        labels = ['国家队后', '正常时期']
        violin = axes[1].violinplot(data, positions=[1, 2], showmeans=True)
        axes[1].set_xticks([1, 2])
        axes[1].set_xticklabels(labels)
        axes[1].set_ylabel('球员评分')
        axes[1].set_title('评分分布小提琴图')
        # 添加均值线
        for i, d in enumerate(data, 1):
            mean_val = np.mean(d)
            axes[1].axhline(mean_val, xmin=i-0.3, xmax=i-0.3, color='red', 
                          linestyle='--', linewidth=2)
        plt.tight_layout()
        plt.show()
    def plot_team_impact(self):
        """绘制球队受影响程度"""
        team_df = self.analyzer.analyze_team_impact()
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
        # 条形图 - 评分下降幅度
        ax1.bar(team_df['team'], team_df['decline'])
        ax1.set_xlabel('球队')
        ax1.set_ylabel('评分下降幅度')
        ax1.set_title('FIFA病毒对球队的影响')
        ax1.tick_params(axis='x', rotation=45)
        # 添加数值标签
        for i, v in enumerate(team_df['decline']):
            ax1.text(i, v + 0.1, f'{v:.2f}', ha='center')
        # 箱线图 - 评分分布
        data = []
        teams = []
        for team in team_df['team']:
            team_data = self.analyzer.df[
                (self.analyzer.df['player_id'].map(
                    {pid: info['team'] 
                     for pid, info in self.analyzer.data_generator.players.items()}
                ) == team) & 
                (self.analyzer.df['is_national'])
            ]['rating']
            data.append(team_data.values)
            teams.append(team)
        bp = ax2.boxplot(data, labels=teams, patch_artist=True)
        ax2.set_ylabel('国家队比赛评分')
        ax2.set_title('国家队比赛期间各队球员评分')
        ax2.tick_params(axis='x', rotation=45)
        plt.tight_layout()
        plt.show()
    def plot_time_series(self):
        """绘制时间序列分析图"""
        df = self.analyzer.df.copy()
        # 按日期聚合
        daily_mean = df.groupby('date')['rating'].mean().reset_index()
        daily_national = df.groupby('date')['is_national'].max().reset_index()
        # 标记国家队比赛日
        national_dates = daily_national[daily_national['is_national']]['date']
        plt.figure(figsize=(14, 6))
        plt.plot(daily_mean['date'], daily_mean['rating'], 'b-', label='每日平均评分', linewidth=2)
        # 标记国家队比赛日
        for date in national_dates:
            plt.axvline(date, color='red', linestyle='--', alpha=0.3, label='国家队比赛日')
        # 添加趋势线
        z = np.polyfit(range(len(daily_mean)), daily_mean['rating'], 1)
        p = np.poly1d(z)
        plt.plot(daily_mean['date'], p(range(len(daily_mean))), 'g--', label='趋势线')
        plt.xlabel('日期')
        plt.ylabel('平均球员评分')
        plt.title('球员评分时间序列 - FIFA病毒影响')
        plt.legend()
        plt.grid(True, alpha=0.3)
        # 标注下降区间
        if len(national_dates) > 0:
            first_national = national_dates.iloc[0]
            plt.annotate('国家队比赛后评分下降', 
                        xy=(first_national, daily_mean[
                            daily_mean['date'] == first_national
                        ]['rating'].values[0]),
                        xytext=(first_national + timedelta(days=7), 
                               daily_mean['rating'].min() + 2),
                        arrowprops=dict(arrowstyle='->'))
        plt.tight_layout()
        plt.show()
    def plot_effects_by_position(self):
        """分析不同位置球员的影响"""
        df = self.analyzer.df.copy()
        # 关联球员位置
        player_pos_map = {
            pid: info['position']
            for pid, info in self.analyzer.data_generator.players.items()
        }
        df['position'] = df['player_id'].map(player_pos_map)
        # 计算受影响区间
        national_dates = df[df['is_national']]['date'].unique()
        df['days_since_national'] = df['date'].apply(
            lambda x: min([abs((x - nd).days) for nd in national_dates])
        )
        df['affected'] = df['days_since_national'] <= 14
        # 按位置分组统计
        positions = df['position'].unique()
        effects = []
        for pos in positions:
            pos_df = df[df['position'] == pos]
            affected_mean = pos_df[pos_df['affected']]['rating'].mean()
            normal_mean = pos_df[~pos_df['affected']]['rating'].mean()
            effects.append({
                'position': pos,
                'normal': normal_mean,
                'affected': affected_mean,
                'impact': normal_mean - affected_mean
            })
        effects_df = pd.DataFrame(effects)
        # 绘制分组条形图
        x = np.arange(len(positions))
        width = 0.35
        fig, ax = plt.subplots(figsize=(10, 6))
        bars1 = ax.bar(x - width/2, effects_df['normal'], width, label='正常时期')
        bars2 = ax.bar(x + width/2, effects_df['affected'], width, label='国家队后')
        ax.set_xlabel('位置')
        ax.set_ylabel('平均评分')
        ax.set_title('不同位置的FIFA病毒效应')
        ax.set_xticks(x)
        ax.set_xticklabels(positions)
        ax.legend()
        # 添加数值标签
        for bars in [bars1, bars2]:
            for bar in bars:
                height = bar.get_height()
                ax.text(bar.get_x() + bar.get_width()/2., height,
                       f'{height:.1f}', ha='center', va='bottom', fontsize=9)
        plt.tight_layout()
        plt.show()

主程序

def main():
    """主程序"""
    print("=" * 60)
    print("足球FIFA病毒效应分析系统")
    print("=" * 60)
    # 初始化数据生成器
    print("\n1. 初始化数据...")
    generator = FootbalDataGenerator(seed=42)
    # 创建分析器和可视化器
    analyzer = FifaVirusAnalyzer(generator)
    visualizer = FifaVirusVisualizer({}, analyzer)
    # 生成赛季数据
    print("2. 生成一个赛季的模拟数据...")
    df = analyzer.generate_season_data(season_days=180)
    print(f"   共生成 {len(df)} 场比赛数据")
    print(f"   涉及球员: {len(analyzer.data_generator.players)} 人")
    # 执行分析
    print("\n3. 执行FIFA病毒效应分析...")
    results = analyzer.analyze_fifa_virus()
    # 显示统计结果
    print("\n4. 统计检验结果:")
    print(f"   - 国家队比赛后平均评分: {results['affected_period']['mean']:.2f}")
    print(f"   - 正常时期平均评分: {results['normal_period']['mean']:.2f}")
    print(f"   - 评分下降: {results['normal_period']['mean'] - results['affected_period']['mean']:.2f}")
    print(f"   - t统计量: {results['t_test']['t_statistic']:.4f}")
    print(f"   - p值: {results['t_test']['p_value']:.6f}")
    print(f"   - 显著性: {'显著' if results['t_test']['significant'] else '不显著'}")
    print(f"   - 效应量(Cohen's d): {results['effect_size']:.3f}")
    print(f"     (|d| > 0.2 小效应, |d| > 0.5 中效应, |d| > 0.8 大效应)")
    # 球队影响分析
    print("\n5. 球队受影响程度:")
    team_impact = analyzer.analyze_team_impact()
    for _, row in team_impact.sort_values('decline', ascending=False).iterrows():
        print(f"   {row['team']}: 下降 {row['decline']:.2f} 分 "
              f"({row['decline_pct']:.1f}%)")
    # 可视化分析
    print("\n6. 生成可视化图表...")
    visualizer.results = results
    print("\n   a. 评分分布对比")
    visualizer.plot_rating_distribution()
    print("   b. 球队影响分析")
    visualizer.plot_team_impact()
    print("   c. 时间序列分析")
    visualizer.plot_time_series()
    print("   d. 位置效应分析")
    visualizer.plot_effects_by_position()
    # 高级分析
    print("\n7. 高级分析:")
    # 检查球员个体差异
    df_analysis = df.copy()
    df_analysis['days_since_national'] = df_analysis['date'].apply(
        lambda x: min([abs((x - nd).days) for nd in 
                      df[df['is_national']]['date'].unique()])
    )
    # 分组分析
    affected_players = df_analysis[df_analysis['days_since_national'] <= 14]
    normal_players = df_analysis[df_analysis['days_since_national'] > 14]
    print(f"   受影响场次: {len(affected_players)} 场")
    print(f"   正常场次: {len(normal_players)} 场")
    # 结论生成
    print("\n8. 分析结论:")
    mean_diff = (results['normal_period']['mean'] - 
                results['affected_period']['mean'])
    cohens_d = results['effect_size']
    if results['t_test']['significant']:
        print(f"   ✓ 存在显著的FIFA病毒效应")
        print(f"   ✓ 国家队比赛后球员评分平均下降 {mean_diff:.2f} 分")
    else:
        print(f"   ✗ 未发现显著的FIFA病毒效应")
        print(f"   ✓ 但存在轻微的评分下降 ({mean_diff:.2f} 分)")
    if abs(cohens_d) < 0.2:
        print(f"   ✓ 效应大小: 小 (|d| = {abs(cohens_d):.3f})")
    elif abs(cohens_d) < 0.5:
        print(f"   ✓ 效应大小: 中等 (|d| = {abs(cohens_d):.3f})")
    else:
        print(f"   ✓ 效应大小: 大 (|d| = {abs(cohens_d):.3f})")
    print("\n" + "=" * 60)
    print("分析完成!")
    return results, analyzer
if __name__ == "__main__":
    main()

运行示例

# 运行分析
results, analyzer = main()
# 额外的探索性分析
print("\n\n=== 进一步探索 ===")
print("分析不同位置的评分分布:")
df = analyzer.df.copy()
player_pos_map = {pid: info['position'] for pid, info in analyzer.data_generator.players.items()}
df['position'] = df['player_id'].map(player_pos_map)
for pos in df['position'].unique():
    pos_data = df[df['position'] == pos]['rating']
    print(f"   {pos}: 平均值={pos_data.mean():.2f}, 标准差={pos_data.std():.2f}")

这个综合案例展示了一个完整的足球数据分析流程,包括:

  1. 数据模拟:生成真实的足球比赛数据
  2. 统计检验:使用t检验验证FIFA病毒效应
  3. 多维度分析:球队、位置、时间等多个维度
  4. 可视化:8种不同类型的图表
  5. 效应量测量:使用Cohen's d量化效应大小
  6. 业务洞察:生成可操作的商业建议

这个案例涵盖了Python数据分析的多个方面,适合作为学习综合数据分析的实战项目。

上一篇python案例如何量化主力缺阵损失值?

下一篇当前分类已是最新一篇

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