2018年世界杯德国竟然输给韩国?终于找到原因了!

程序员宝藏库github.com/Jackpopc/CS…

大家好,我是Jackpop。

今天来跟大家聊一下足球。

首先表明,我并不是一个足球爱好者。

我很少关注世界杯、欧冠这些名气较大的足球比赛,更不会去留意国足相关的内容。

虽然对于足球比赛竞技本身并不感兴趣,但是作为一个数据科学领域的开发人员,对比赛背后的数据还是充满着浓厚的兴趣。

数据科学是一种从数据中挖掘和捕捉有价值信息的方法,数据科学正在影响着许多领域,这也包括足球。

足球包含大量的数据,从个人到团队方面都有涉及。有了这些数据,我们就能以一种更有意义的方式了解比赛。

另外,对于球队来说,数据可以创造出指导决策的信息。

因此,团队可以找到赢得比赛的策略。

在这篇文章中,我将带你了解如何使用Python分析足球赛事数据。

在这里,我们将分析2018年国际足联世界杯德国和韩国的比赛。

不用多说,让我们开始吧!

数据获取

对于数据,我们将使用StatsBomb的数据。

StatsBomb是一家专门在足球领域工作的分析公司,他们提供了大量的足球数据,尤其是事件数据。

对于那些想学习足球分析的人来说,得益于StatsBomb已经公布了公开数据,能够节省很多获取数据的时间。

这些数据由已经结束的足球联赛的比赛组成,数据链接:github.com/statsbomb/o…

注意:在获取数据时,请耐心等待,因为数据量真的很大。

数据探索

在你下载数据后,下一步是探索它。

数据的文件夹结构如下所示:

|   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
复制代码

还有一些文件夹,如事件(events)、阵容(lineups)和比赛(matches):

  • 事件文件夹包含以JSON格式回顾比赛的文件
  • 阵容文件夹包含每场比赛中各队的阵容
  • 比赛文件夹包含每场比赛的比赛。它也被分为几个比赛的不同季节

那么,在数据里面有很多文件的情况下,我们怎样才能检索到一个特定的比赛呢?正如我之前提到的,我们将分析德国和韩国的世界杯比赛。

在下一步,我将告诉你如何检索数据。

数据检索

事件数据可以通过以下步骤来检索。

首先,我们打开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提供的所有比赛信息的行。

img

总之,这些数据中包括的比赛有西甲(西班牙联赛)、欧洲杯、国际足联世界杯(男子和女子)以及欧洲冠军联赛。

现在,我们想取有国际足联世界杯信息的那一行。

让我们用下面这行代码来过滤数据集。

# Get the FIFA World Cup
competition[competition.competition_name == 'FIFA World Cup']
复制代码

img

从上面可以看出,国际足联世界杯的比赛和赛季的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
复制代码

哇,你会发现,这是个很大的数据,而且读起来很混乱。

让我们首先通过使用循环来整理它。

在每一次迭代中,我们都要取得比赛的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()
复制代码

img

比以前更有可读性,接下来让我们从数据中创建一些可视化的东西。

数据可视化

我们可以创建的可视化之一是射门图。

在这张图上,我们想看看每支球队有多少次射门。此外,还想知道进球的几率有多大,我们称这种机会为预期进球。

为了创建可视化,我们需要首先获取事件数据。然后,根据事件名称来过滤数据。

在这种情况下,我们需要射门的相关数据:

shots = df[df.type_name == 'Shot'].set_index('id')
shots.head()
复制代码

img

在我们得到数据后,现在让我们来写这些代码,对数据进行可视化:

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资源库](SoccermaticsForPython/FCPython.py at master · Friends-of-Tracking-Data-FoTD/SoccermaticsForPython · GitHub)。

为了生成圆点,我们需要遍历dataframe中的数据行。对于每一次迭代,需要做如下两件事情:

  • 把坐标和预期目标(xG)值一起拿出来。
  • 根据前面的参数生成一个圆。xG值将被用作圆圈大小的值,我们还为不是进球的射门设置透明度。

如果你的代码写得正确,它应该产生一个像下面这样的效果图:

img

现在我们可以从数据中得到启示。

正如我们从上面看到的,我们知道德国有很多的机会,但他们无法从中获得任何进球。

另外,他们有几次射门的xG值很大。xG值越大,进球的机会就越大。但不幸的是,德国人无法将其转换为进球。

在韩国方面,我们可以看到,他们没有很多机会。他们也不像德国人那样每次射门都有巨大的预期进球。

但是,在比赛结束时,德国队犯了一些错误,导致了一个尴尬的结果。最后,孙兴民和金英权成了韩国队的英雄。

结语

这是你可以创建的可视化之一,我们可以做的数据可视化有很多。

除此之外,我们可以做一个传球热图,或者进球过程中的控球链,或者每个球员的传球图。

正如我之前所说,足球赛事数据有很多值得挖掘的信息。

因此,这有助于团队和外面的足球爱好者更加了解这个比赛。

现在你已经学会了如何用Python分析StatsBomb的足球事件数据。

我希望它能激励你开始使用Python分析体育数据,特别是足球。


大家好,我是Jackpop!我花费了半个月的时间把这几年来收集的各种技术干货整理到一起,其中内容包括但不限于Python、机器学习、深度学习、计算机视觉、推荐系统、Linux、工程化、Java,内容多达5T+,获取方式:pan.baidu.com/s/1eks7CUyj…

Guess you like

Origin juejin.im/post/7033782107574894599