程序员宝库:github.com/Jackpopc/CS-Books-Store
大家好,我是杰克波普。
今天和大家聊聊足球。
首先,我不是足球迷。
很少关注世界杯、欧冠等足球名场赛事,更不会去关注与国足相关的内容。
虽然我对足球比赛本身不感兴趣,但作为数据科学领域的开发者,我还是对比赛背后的数据很感兴趣。
数据科学是一种从数据中挖掘和捕获有价值信息的方法。数据科学正在影响许多领域,其中包括足球。
足球包含大量数据,从个人到球队。有了这些数据,我们就能以更有意义的方式理解游戏。
此外,对于团队而言,数据可以创建指导决策的信息。
因此,团队可以找到赢得比赛的策略。
在本文中,我将向您介绍如何使用 Python 分析足球数据。
下面我们来分析一下2018年世界杯德国队和韩国队的比赛。
事不宜迟,让我们开始吧!
数据采集
对于数据,我们将使用 StatsBomb 中的数据。
StatsBomb 是一家专门从事足球的分析公司18年世界杯比赛结果比分表,他们提供大量的足球数据,尤其是赛事数据。
对于想要学习足球分析的同学来说,得益于StatsBomb公开了数据,可以节省很多获取数据的时间。
数据包括已经结束的足球联赛比赛,数据链接:github.com/statsbomb/open-data
注意:取数据时,请耐心等待,因为数据量确实很大。数据探索
下载数据后,下一步就是探索它。
数据的文件夹结构如下:
| LICENSE.pdf
| README.md
|
+---data
| | competitions.json
| |
| +---events
| | 15946.json
| | 15956.json
| | 15973.json
| | 15978.json
| | 15986.json
| |
| +---lineups
| | 15946.json
| | 15956.json
| | 15973.json
| | 15978.json
| | 15986.json
| |
| ---matches
| +---11
| | 1.json
| | 2.json
| |
| +---16
| | 1.json
| | 2.json
| |
|
+---doc
| Open Data Competitions v2.0.0.pdf
| Open Data Events v4.0.0.pdf
| Open Data Lineups v2.0.0.pdf
| Open Data Matches v3.0.0.pdf
| StatsBomb Open Data Specification v1.1.pdf
|
---img
statsbomb-logo.jpg
还有事件、阵容和比赛等文件夹:
那么当数据中有很多文件时,我们如何检索特定的匹配项呢?正如我之前提到的,我们将分析德国和韩国的世界杯比赛。
在下一步中,我将向您展示如何检索数据。
数据检索
可以通过以下步骤检索事件数据。
首先,我们打开 competitions.json 文件。该文件是访问 StatsBomb 数据的第一步。
这样做的原因是我们需要从中获取比赛列表的比赛和赛季 ID。
为了处理 JSON 文件,pandas 库提供了使用 read_json 函数将 JSON 文件读入 DataFrame 的函数:
import pandas as pd
competition = pd.read_json('open-data/data/competitions.json')
competition.head()
现在,您可以看到包含 StatsBomb 提供的所有匹配信息的一行。
综上所述,这些数字中包含的比赛是西甲(西班牙联赛)、欧洲杯、国际足联世界杯(男女)和欧洲冠军联赛。
现在,我们要获取包含有关 FIFA 世界杯信息的行。
让我们使用以下代码行过滤数据集。
# Get the FIFA World Cup
competition[competition.competition_name == 'FIFA World Cup']
如上所示,FIFA 世界杯比赛和赛季的 ID 分别为 43 和 3。
现在让我们访问包含 ID 的文件夹。
对于每场比赛,文件夹以比赛 ID 命名,每个文件夹都包含 JSON 文件。
每个文件都是一个以季节 ID 命名的附件。
现在让我们使用以下几行代码访问该文件:
import json
with open('open-data/data/matches/43/3.json') as f:
data = json.load(f)
data
哇,你看,那是很多数据18年世界杯比赛结果比分表,而且读起来很混乱。
让我们先用一个循环来整理一下。
在每次迭代中,我们需要获取游戏的 ID、球队名称和分数:
with open('open-data/data/matches/43/3.json') as f:
data = json.load(f)
for i in data:
print('ID:', i['match_id'], i['home_team']['home_team_name'], i['home_score'], '-', i['away_score'], i['away_team']['away_team_name'])
现在,它比以前更整洁了。
再来看看德国队和韩国队的比赛。
最终比分2-0,韩国队获胜(你可能不知道,德国队和韩国队的比赛很精彩)。
这一结果也见证了德国人自 1938 年以来首次在小组赛首轮出局。
回到正题,德国对韩国的比赛ID是7567。
使用以下代码行访问此文件:
with open('open-data/data/events/7567.json') as f:
korger = json.load(f)
korger
这比之前的数据要多得多。
为了方便我们分析,pandas库提供了json_normalize函数,这个函数之所以强大,是因为它可以处理嵌套的JSON。
现在让我们编写这些代码行:
# from pandas.io.json import json_normalize
df = pd.json_normalize(korger, sep='_').assign(match_id="7567")
df.head()
比以前更具可读性,让我们从数据中创建一些可视化。
数据可视化
我们可以创建的可视化之一是镜头图。
在这个图表上,我们想看看每支球队有多少投篮。另外,我们还想知道进球的概率是多少,我们称之为预期进球。
为了创建可视化,我们需要先获取事件数据。然后,根据事件名称过滤数据。
在这种情况下,我们需要有关镜头的数据:
shots = df[df.type_name == 'Shot'].set_index('id')
shots.head()
现在我们有了数据,让我们编写这段代码来可视化数据:
import numpy as np
import matplotlib.pyplot as plt
from FCPython import createPitch
pitch_width = 120
pitch_height = 80
fig, ax = createPitch(pitch_width, pitch_height, 'yards', 'gray')
home_team = 'South Korea'
away_team = 'Germany'
for i, shot in shots.iterrows():
x = shot['location'][0]
y = shot['location'][1]
goal = shot['shot_outcome_name']=='Goal'
team_name = shot['team_name']
circle_size = 2
circle_size = np.sqrt(shot['shot_statsbomb_xg'] * 15)
if team_name == home_team:
if goal:
shot_circle = plt.Circle((x, pitch_height-y), circle_size, color='red')
plt.text((x+1), pitch_height-y+1, shot['player_name'])
else:
shot_circle = plt.Circle((x, pitch_height-y), circle_size, color='red')
shot_circle.set_alpha(.2)
elif team_name == away_team:
if goal:
shot_circle = plt.Circle((pitch_width-x, y), circle_size, color='blue')
plt.text((pitch_width-x+1), y+1, shot['player_name'])
else:
shot_circle = plt.Circle((pitch_width-x, y), circle_size, color='blue')
shot_circle.set_alpha(.2)
ax.add_patch(shot_circle)
plt.text(5, 75, away_team + ' shots')
plt.text(80, 75, home_team + ' shots')
plt.title('Germany vs South Korea at 2018 FIFA World Cup')
fig.set_size_inches(10, 7)
fig.savefig('korger_shots.png', dpi=300)
plt.show()
我先解释一下代码。
首先,打造一个足球场。然后,还创建一个点集合,对应于已拍摄的镜头。
要创建这个音调,我们可以使用 FCPython 中的 createPitch 函数。
对于 FCPython,您可以在此处查看 GitHub 存储库。
为了生成点,我们需要遍历数据框中的数据行。对于每次迭代,需要做两件事:
如果您的代码编写正确,它应该生成如下所示的图:
现在我们可以从数据中得到提示。
正如我们在上面看到的,我们知道德国有很多机会,但他们无法从中获得任何进球。
另外,他们有几个 xG 值很大的镜头。xG值越大,进球的机会就越大。但不幸的是,德国人无法将其转化为进球。
在韩国方面,我们可以看到他们没有太多机会。他们也不像德国人那样每次射门都有巨大的预期目标。
不过在比赛最后阶段,德国队出现了一些失误,导致了一个尴尬的结果。最终,孙兴慜和金英权成为了韩国队的功臣。
结语
这是您可以创建的可视化之一,我们可以做很多数据可视化。
除此之外,我们可以做一个传球热力图,或者得分过程中的控球链,或者每个球员的传球图。
正如我之前所说,足球数据有很多值得挖掘的信息。
因此,它可以帮助球队和球迷更好地了解比赛。
您现在已经了解了如何使用 Python 分析 StatsBomb 的足球赛事数据。
我希望它能激发您开始使用 Python 分析体育数据,尤其是足球数据。
大家好,我是Jackpop!我花了半个月的时间整理了这几年收集的各种技术干货,包括但不限于Python、机器学习、深度学习、计算机视觉、推荐系统、Linux、工程、Java,内容高达5T+,获取方式:pan.baidu.com/s/1eks7CUyjbWQ3A7O9cmYljA(提取码:0000)