编程实战:用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