世界杯:西班牙vs佛得角

作者:







编程实战:用Python分析足球比赛数据——以西班牙vs佛得角为例


编程实战:用Python分析足球比赛数据——以西班牙vs佛得角为例

简介

足球数据分析已成为现代体育的重要组成部分。本文将以2026美加墨世界杯小组赛H组西班牙对阵佛得角的比赛为例,教你如何使用Python获取、处理和分析足球比赛数据。我们将使用公开的足球数据API,结合pandas进行数据清洗,matplotlib进行可视化,最终生成直观的比赛统计图表。

无论你是足球爱好者还是数据分析师,这篇教程都能帮助你掌握处理体育数据的基本技能。

前置准备

在开始之前,请确保你的开发环境满足以下要求:

1. Python环境

安装Python 3.8或更高版本。建议使用虚拟环境:

python -m venv football_analysis
source football_analysis/bin/activate  # Linux/Mac
# 或 football_analysis\Scripts\activate  # Windows

2. 必要库安装

pip install requests pandas matplotlib seaborn beautifulsoup4

3. 数据源选择

我们将使用免费的足球数据API,如:
API-Football:提供详细的比赛统计
Football-data.org:开源足球数据
StatsBomb Open Data:高质量事件数据

4. 推荐开发工具

为了提高开发效率,以下工具很有帮助:

  • 机械键盘:舒适的键盘能提升编码效率,推荐机械键盘
  • 显示器:大尺寸显示器便于查看数据可视化和代码
  • 笔记本电脑:性能足够的笔记本电脑是数据分析的基础

第一步:获取比赛数据

首先,我们需要获取西班牙vs佛得角比赛的基本信息和统计数据。

import requests
import pandas as pd
from datetime import datetime

def get_match_data(match_id):
    """
    从API获取比赛数据
    这里以模拟数据为例,实际使用时替换为真实API调用
    """
    # 模拟数据 - 实际项目中应替换为真实API调用
    match_data = {
        "match_info": {
            "home_team": "西班牙",
            "away_team": "佛得角",
            "date": "2026-06-16T00:00:00Z",
            "venue": "MetLife Stadium",
            "competition": "世界杯小组赛H组",
            "stage": "小组赛第1轮"
        },
        "statistics": {
            "possession": {"home": 72, "away": 28},
            "total_shots": {"home": 18, "away": 5},
            "shots_on_target": {"home": 8, "away": 2},
            "corners": {"home": 9, "away": 3},
            "fouls": {"home": 10, "away": 14},
            "yellow_cards": {"home": 2, "away": 3},
            "passes": {"home": 625, "away": 280},
            "pass_accuracy": {"home": 89, "away": 75}
        },
        "events": [
            {"time": "23'", "event": "进球", "team": "西班牙", "player": "佩德里"},
            {"time": "45'+2", "event": "进球", "team": "西班牙", "player": "莫拉塔"},
            {"time": "67'", "event": "进球", "team": "西班牙", "player": "费兰·托雷斯"},
            {"time": "78'", "event": "黄牌", "team": "佛得角", "player": "门德斯"},
            {"time": "85'", "event": "进球", "team": "西班牙", "player": "加维"}
        ]
    }

    return match_data

# 获取比赛数据
match_id = "spain_vs_cape_verde_20260616"
match_data = get_match_data(match_id)
print("比赛数据获取成功!")

第二步:数据清洗与处理

获取原始数据后,我们需要将其转换为更适合分析的格式。

import json
from datetime import datetime

def process_match_data(raw_data):
    """
    处理和清洗比赛数据
    """
    # 1. 转换日期格式
    match_info = raw_data["match_info"]
    match_info["date_obj"] = datetime.fromisoformat(
        match_info["date"].replace("Z", "+00:00")
    )
    match_info["formatted_date"] = match_info["date_obj"].strftime("%Y-%m-%d %H:%M")

    # 2. 将统计数据转换为DataFrame
    stats = raw_data["statistics"]
    stats_data = []

    for stat_name, values in stats.items():
        for team, value in values.items():
            stats_data.append({
                "statistic": stat_name,
                "team": "西班牙" if team == "home" else "佛得角",
                "value": value
            })

    stats_df = pd.DataFrame(stats_data)

    # 3. 处理比赛事件
    events_df = pd.DataFrame(raw_data["events"])

    # 提取分钟数用于时间线分析
    def extract_minute(time_str):
        # 处理加时情况如"45'+2"
        if "'" in time_str:
            base = time_str.split("'")[0]
            if "+" in base:
                return int(base.split("+")[0]) + int(base.split("+")[1])
            return int(base)
        return 0

    events_df["minute"] = events_df["time"].apply(extract_minute)
    events_df["minute"] = events_df["minute"].astype(int)

    # 4. 计算关键指标
    possession_home = stats["possession"]["home"]
    possession_away = stats["possession"]["away"]

    stats_summary = {
        "total_goals": len([e for e in raw_data["events"] if e["event"] == "进球"]),
        "goals_home": len([e for e in raw_data["events"] 
                          if e["event"] == "进球" and e["team"] == "西班牙"]),
        "goals_away": len([e for e in raw_data["events"] 
                          if e["event"] == "进球" and e["team"] == "佛得角"]),
        "possession_diff": possession_home - possession_away,
        "shot_accuracy_home": (stats["shots_on_target"]["home"] / 
                              stats["total_shots"]["home"] * 100),
        "shot_accuracy_away": (stats["shots_on_target"]["away"] / 
                              stats["total_shots"]["away"] * 100)
    }

    return {
        "match_info": match_info,
        "stats_df": stats_df,
        "events_df": events_df,
        "stats_summary": stats_summary
    }

# 处理数据
processed_data = process_match_data(match_data)
print("数据处理完成!")
print(f"比赛时间:{processed_data['match_info']['formatted_date']}")
print(f"总进球数:{processed_data['stats_summary']['total_goals']}")

第三步:数据可视化

现在让我们用图表直观展示比赛数据。

import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.font_manager import FontProperties

# 设置中文显示(如果系统支持)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

def create_match_visualizations(data):
    """
    创建比赛数据可视化图表
    """
    stats_df = data["stats_df"]
    events_df = data["events_df"]
    summary = data["stats_summary"]

    # 创建2x2子图布局
    fig, axes = plt.subplots(2, 2, figsize=(15, 12))
    fig.suptitle('西班牙 vs 佛得角 比赛数据分析', fontsize=16, fontweight='bold')

    # 1. 控球率和关键统计对比
    ax1 = axes[0, 0]
    key_stats = ['possession', 'total_shots', 'corners', 'passes']
    key_stats_df = stats_df[stats_df['statistic'].isin(key_stats)]

    sns.barplot(x='statistic', y='value', hue='team', data=key_stats_df, 
                palette=['#FFD700', '#FF4444'], ax=ax1)
    ax1.set_title('关键比赛数据对比', fontsize=12)
    ax1.set_xlabel('统计项')
    ax1.set_ylabel('数值')
    ax1.legend(title='球队')

    # 2. 进球时间线
    ax2 = axes[0, 1]
    goals = events_df[events_df['event'] == '进球']

    for team, color in [('西班牙', '#FFD700'), ('佛得角', '#FF4444')]:
        team_goals = goals[goals['team'] == team]
        if not team_goals.empty:
            ax2.scatter(team_goals['minute'], [1]*len(team_goals), 
                       s=200, c=color, label=team, zorder=5)
            for _, row in team_goals.iterrows():
                ax2.annotate(f"{row['player']}\n{row['time']}", 
                            (row['minute'], 1), 
                            textcoords="offset points", 
                            xytext=(0,15), ha='center')

    ax2.set_xlim(0, 95)
    ax2.set_ylim(0, 2)
    ax2.set_xlabel('比赛时间(分钟)')
    ax2.set_yticks([])
    ax2.set_title('进球时间线', fontsize=12)
    ax2.legend()
    ax2.axvline(x=45, color='gray', linestyle='--', alpha=0.5)
    ax2.axvline(x=90, color='gray', linestyle='--', alpha=0.5)
    ax2.text(45, 0.5, '半场', ha='center', va='center', alpha=0.5)

    # 3. 射门效率分析
    ax3 = axes[1, 0]
    shot_data = stats_df[stats_df['statistic'].isin(['total_shots', 'shots_on_target'])]

    teams = ['西班牙', '佛得角']
    total_shots = []
    shots_on_target = []

    for team in teams:
        total = shot_data[(shot_data['team'] == team) & 
                         (shot_data['statistic'] == 'total_shots')]['value'].values[0]
        on_target = shot_data[(shot_data['team'] == team) & 
                             (shot_data['statistic'] == 'shots_on_target')]['value'].values[0]
        total_shots.append(total)
        shots_on_target.append(on_target)

    x = range(len(teams))
    width = 0.35

    ax3.bar(x, total_shots, width, label='总射门', color=['#FFD700', '#FF4444'], alpha=0.7)
    ax3.bar([i + width for i in x], shots_on_target, width, label='射正', 
            color=['#FFD700', '#FF4444'])

    ax3.set_xlabel('球队')
    ax3.set_ylabel('射门次数')
    ax3.set_title('射门效率分析', fontsize=12)
    ax3.set_xticks([i + width/2 for i in x])
    ax3.set_xticklabels(teams)
    ax3.legend()

    # 4. 统计摘要
    ax4 = axes[1, 1]
    ax4.axis('off')  # 隐藏坐标轴

    summary_text = f"""
    比赛统计摘要
    ==============
    最终比分:西班牙 {summary['goals_home']} - {summary['goals_away']} 佛得角
    控球率差异:{summary['possession_diff']:.1f}%
    西班牙射正率:{summary['shot_accuracy_home']:.1f}%
    佛得角射正率:{summary['shot_accuracy_away']:.1f}%
    总进球数:{summary['total_goals']}

    比赛时间:2026年6月16日 00:00
    赛事:世界杯小组赛H组第1轮
    """

    ax4.text(0.1, 0.5, summary_text, fontsize=12, verticalalignment='center',
            bbox=dict(boxstyle="round,pad=0.5", facecolor="lightgray", alpha=0.8))
    ax4.set_title('比赛统计摘要', fontsize=12)

    plt.tight_layout()
    plt.savefig('spain_vs_cape_verde_analysis.png', dpi=300, bbox_inches='tight')
    plt.show()

    print("可视化图表已保存为 'spain_vs_cape_verde_analysis.png'")

# 创建可视化
create_match_visualizations(processed_data)

第四步:深入分析与报告生成

让我们进行更深入的分析并生成完整的比赛报告。

“`python
def generate_match_report(data):
“””
生成详细的比赛分析报告
“””
match_info = data[“match_info”]
stats_df = data[“stats_df”]
events_df = data[“events_df”]
summary = data[“stats_summary”]

# 创建分析报告
report = f"""

{match_info[‘home_team’]} vs {match_info[‘away_team’]} 比赛分析报告

比赛基本信息

  • 比赛时间:{match_info[‘formatted_date’]}
  • 比赛地点:{match_info[‘venue’]}
  • 赛事阶段:{match_info[‘competition’]} {match_info[‘stage’]}

比赛结果

最终比分:{summary[‘goals_home’]} – {summary[‘goals_away’]}

关键数据对比

统计项 西班牙 佛得角 差异
”“”
# 添加统计数据到报告
key_stats = ['possession', 'total_shots', 'shots_on_target', 'corners', 'passes']
for stat in key_stats:
    home_val = stats_df[(stats_df['statistic'] == stat) & 
                      (stats_df['team'] == '西班牙')]['value'].values[0]
    away_val = stats_df[(stats_df['statistic'] == stat) & 
                      (stats_df['team'] == '佛得角')]['value'].values[0]
    diff = home_val - away_val

    # 格式化统计项名称
    stat_name = stat.replace('_', ' ').title()
    if stat == 'possession':
        stat_name = '控球率'
        home_val = f"{home_val}%"
        away_val = f"{away_val}%"
        diff = f"{diff}%"

    report += f"| {stat_name} | {home_val} | {away_val} | {diff} |\n"

# 添加进球详情
report += "\n## 进球详情\n"
goals = events_df[events_df['event'] == '进球']
for _, goal in goals.iterrows():
    report += f"- {goal['time']} {goal['team']} - {goal['player']}\n"

# 添加分析总结
report += f"""

比赛分析

1. 比赛进程

西班牙队从比赛开始就占据主动,控球率高达{stats_df[(stats_df[‘statistic’] == ‘possession’) & (stats_df[‘team’] == ‘西班牙’)][‘value’].values[0]}%。
球队通过精准的传递控制比赛节奏,上半场结束时已取得2-0领先。

2. 战术特点

  • 西班牙:采用传统的控球战术,短传配合流畅
  • 佛得角:防守反击为主,尝试利用身体优势

3. 关键球员

西班牙中场核心佩德里表现出色,不仅打入首球,还多次创造机会。
佛得角门将虽做出多次扑救,但仍难以抵挡西班牙的持续进攻。

4. 统计分析

西班牙在射门次数({stats_df[(stats_df[‘statistic’] == ‘total_shots’) & (stats_df[‘team’] == ‘西班牙’)][‘value’].values[0]})和射正次数({stats_df[(stats_df[‘statistic’] == ‘shots_on_target’) & (stats_df[‘team’] == ‘西班牙’)][‘value’].values[0]})上均占明显优势。
传球成功率方面,西班牙达到{stats_df[(stats_df[‘statistic’] == ‘pass_accuracy’) & (stats_df[‘team’] == ‘西班牙’)][‘value’].values[0]}%,展现出高质量的传控能力。

结论

西班牙队在这场比赛中展现了强大的控制力和进攻效率,顺利取得世界杯开门红。
佛得角虽然实力处于下风,但球员们展现了良好的拼搏精神。

报告生成时间:{datetime.now().strftime(“%Y-%m-%d %H:%M:%S”)}
数据分析工具:Python + Pandas + Matplotlib
“”“

# 保存报告
with open("spain_vs_cape_verde_report.md", "w", encoding="utf-8") as f:
    f