当前位置:首页 > 足球资讯 > 正文内容

Soccermatics之一:使用python分析足球数据集

杏彩体育2年前 (2023-03-01)足球资讯102

开始之前

本篇假设读者熟悉python编程、matplotlib和pandas软件包的使用

鸣谢

本篇的内容部分参考了Soccermatics(https://soccermatics.readthedocs.io);

数据集使用了Statsbomb公司(https://www.statsbomb.com)的开放数据(https://github.com/statsbomb/open-data)。

我们可以分析些什么?

利用丰富的球场比赛数据,可以分析射门瞬间,防守进攻的各种选择;分析传球网络图、球场热点;计算射门预期进球,评价球员控球或无球跑动,量化球员招募等等。

开发环境

基础环境

python环境

python3.10 venv,推荐ubuntu,安装软件包方便快捷,非常适合用作开发环境,直接在应用商店中安装,不需要使用浏览器下载软件安装包。

如果系统已经安装了python的软件包virtualenv,则可以使用如下命令创建并激活虚拟运行环境(假设所有的数据和代码都存放在eda目录下):

mkdir eda cd eda python3.10 -m venv env source env/bin/activate

科学计算四件套:numpy、scipy、matplotlib、pandas,这几个软件包可以直接在python虚拟运行环境中安装:

pip install -U numpy scipy matplotlib pandas

推荐使用poetry来管理软件包,pyenv管理虚拟运行环境。

足球数据分析软件之mplsoccer

mplsoccer(https://github.com/andrewRowlinson/mplsoccer)是基于画图软件matplotlib的足球可视化软件,除了可以展示球场为基础的数据之外,还支持多种面向球赛/球员统计数据的图表。mplsoccer还可以直接读取解析足球数据提供商statsbomb的数据,但本篇中没有使用mplsoccer的这项功能。

足球分析软件kloppy

kloppy(https://github.com/PySport/kloppy)是设计用来统一访问多个足球数据集提供商的访问库。不同的最取数据服务商的数据在格式和描述方式上有区别,如果需要来自多个服务商的数据或者需要切换数据服务商,则代码会比较混乱。kloppy提供了数据的序列化/反序列化、标准数据描述模型、数据过滤/转换器等一系列功能,使读取足球数据方便快捷。

其他配套软件视个人喜好:编辑器Microsoft vscode以及相关插件,python软件包jupyter等。

足球数据集

足球的数据种类很多,涵盖了球队战绩、球员能力等各个方面,但要是想详细分析某一长球赛的细节,目前用来分析的主要是下面几种数据。

事件数据

事件数据详细描述了一场球赛中的每一次球处理的详细信息,比如传球、射门、盘带、争顶等,每次事件包含了时间、球员、球场坐标等,以及其他详细信息。事件数据是由数据提供商从比赛录像中人工提取,一般来说一场比赛会包含数千个事件。

显然事件数据需要成本,但近年来一些数据服务商免费提供了一些公开数据,这些免费的公开数据主要有:

statsbomb

赛事比赛数量赛季男足世界杯642018欧洲杯512020英超(阿森纳)3303/04西甲(梅西)52004/05 – 20/21欧冠(决赛)1499/00 – 18/19女足世界杯522019美国国家联赛362018英超32618/19 – 20/21合计1096

数据下载页面(https://github.com/statsbomb/open-data

wyscout

赛事比赛数量赛季法甲38017/18英超38017/18意甲38017/18西甲38017/18德甲30617/18世界杯642018欧洲杯512016合计1941

数据下载页面(https://github.com/koenvo/wyscout-soccer-match-event-dataset)

追踪数据

跟踪数据是将球赛每时每刻的球员和足球的位置坐标都记录下来,每秒25帧!

免费的追踪数据主要有:

metrica sport

这个公开数据包含了三场匿名的比赛追踪数据,帧速为25Hz,除了场上所有球员的追踪数据外,还提供了与追踪数据时间对齐的事件数据。

数据下载链接(https://github.com/metrica-sports/sample-data)

skillcorner

SkillCorner的免费数据包含了9场比赛,帧速为10Hz。数据是从直播镜头中采集,因此数据只包含了位于镜头中的球员。

数据下载链接(https://github.com/SkillCorner/opendata)

事件数据往往具备语义,适合做机器统计分析,虽然不同提供商的语义模型稍有差异;而追踪数据包含了每刻球员的位置没有包含语义,适合进行人工分析;如果事件数据和追踪数据的时间轴是对齐的,配合起来更加强大。

开始数据分析

Statsbomb数据集更新频繁,数据丰富,还包含了其特有的360数据帧。360数据记录了该事件发生时其他球员的位置,使态势分析更加有依据。StatsBomb 的公开数据为 2020 年欧洲杯的 51 场比赛提供了360数据帧。

开放数据的每次射门事件还包含了Statsbomb根据自己的模型计算出的期望进球概率(Expected Goals, xG)数据。

本篇使用了Statsbomb的公开数据集。

Statsbomb数据说明

由于数据访问涉及到球场坐标,因此球场大小、进攻方向和坐标系统就尤为重要。不幸的事,这事还没有标准可言,目前不同的数据提供商都自有一套。有的厂商坐标原点是左上,有的是左下,有的坐标范围是[0,1],有的是标准球场尺寸坐标,因此在处理数据过程中特别需要注意。

下图的球场尺寸是来自Statsbomb开放数据中的数据规范:

球门尺寸:

Statsbomb的位置坐标是按照以球场左上为原点,球场大小为120×80来记录的。

注意:Statsbomb的长度单位是码(yard),在必要的时候,我们需要将其转换为米,以米为单位的标准球场大小是105×68。

注意:数据中记录的位置数据,在进攻(射门事件)时,不论主队客队,进攻方向总是从左往右的,也就是说射门事件中,一般来说x坐标都在100左右。

数据按照赛事、赛季和比赛进行组织,采用json格式文件来描述。

赛事和赛季数据保存在competitions.json文件中,每个赛事、赛季、比赛、球员都有一个id标识。

每个赛事和赛季的比赛存放在matches目录中,按照赛事id目录存放了比赛的元数据。

在events和lineups目录中,按照比赛id存放了每个比赛的事件和阵容数据。

在使用数据之前,使用json数据查看器看一下数据的大概内容,对格式和描述内容有个大概了解,从文件中可以看出,数据的可读性非常好,也有大量冗余数据,适合人去理解。

同时浏览一下开放数据中包含的数据规范。

使用kloppy

数据加载

假设你的网络可以很顺利的访问github,那么我们就可以很顺利的加载数据了:

from kloppy import statsbomb # 从开放数据中加载id为7559的比赛数据 # 只加载类型为pass(传球)和shot(射门)这两类事件 # 数据中的坐标系统采用statsbomb坐标系统 dataset = statsbomb.load_open_data(match_id=7559,coordinates=statsbomb,event_types=[pass, shot])

也可以把开放数据从github克隆到本机,然后采用使用kloppy进行加载

match_id = 68366 base_url = /location/to/you/data/statsbomb/data dataset = statsbomb.load( event_data=os.path.join(base_url, events/%s.json%match_id), lineup_data=os.path.join(base_url, lineups/%s.json%match_id), # 转换为kloppy自己的坐标系统 coordinates=kloppy )

kloppy设计了一套标准数据模型,来适应不同数据服务商的数据。

标准数据模型包含了如下类型的事件:ShotEvent、PassEvent以及GenericEvent(不识别的其他类型事件都放在这里面)等13种,大大少于各数据服务商自行定义的事件类型。那如何访问标准数据模型之外的其他数据?

第一种方法:直接访问

e.raw_event[play_pattern]

raw_event属性保存的原始的事件,在需要时根据Statsbomb数据规范进行访问,但要注意这里面的数据没有经过kloppy的处理转换,使用时要小心。

第二种方法,使用EventFactory。通过EventFactory将raw_event中需要的数据增加为事件的属性。

match_id = 7559 base_url = /location/to/you/data/statsbomb/data import os from kloppy import statsbomb from dataclasses import dataclass from kloppy.domain import EventFactory, create_event, ShotEvent, PassEvent, EventDataset @dataclass(repr=False) class StatsBombShotEvent(ShotEvent): statsbomb_xg: float = None class StatsBombEventFactory(EventFactory): def build_shot(self, **kwargs) -> ShotEvent: kwargs[statsbomb_xg] = kwargs[raw_event][shot][statsbomb_xg] kwargs[body_part_type] = kwargs[raw_event][shot][body_part][name] return create_event(StatsBombShotEvent, **kwargs) event_factory = StatsBombEventFactory() dataset = statsbomb.load( event_data=os.path.join(base_url, events/%s.json%match_id), lineup_data=os.path.join(base_url, lineups/%s.json%match_id), event_types=[shot] coordinates=statsbomb, event_factory=event_factory )

这样得到的dataset中的事件就包含了statsbomb_xg期望进球概率和body_part_type进球部位这两个属性,不需要访问raw_event属性了。

数据转换

加载数据操作load返回kloppy事件数据集EventDataset可以使用迭代器进行访问,可以使用进行过滤,也可以使用查找,还可以通过某个事件获取关联事件。

# 过滤出所有的射门事件中的进球事件 filtered_dataset = dataset.filter(shot.goal) # 查找出所有的传球事件 passes = dataset.find_all(pass) # 从某一事件中获取关联事件 events = event.get_related_events()

通常对EventDataset进行过滤或者查找之后转换为pandas DataFrame。

转换操作to_df可以将数据集的指定属性转换成DataFrame

dataset.to_df( period_id, timestamp, *coordinates*, )

可以指定需要保留到DataFrame中的列名称或者名称通配符,还可以通过lambda进行转换:

dataset.to_df( # 将事件的某些属性转换为df的列 lambda event: {period: event.period.id, timestamp: event.timestamp}, # 直接指定列常量 some_columns=1234, # 可调用的列 other_column=lambda x: random.randint(0, 255) )

而to_pandas操作可以将事件的所有属性转换为DataFrame的列,并可以增加一些其他列:

dataframe = dataset.to_pandas( additional_columns={ player_name: lambda event: str(event.player), team_name: lambda event: str(event.player.team) } )

具体可以参考kloppy的文档页面。

使用mplsoccer

mplsoccer画出一个球场非常简单:

from mplsoccer.pitch import Pitch pitch = Pitch(pitch_color=grass, line_color=white, stripe=True) fig, ax = pitch.draw()

效果如下:

_images/sphx_glr_plot_quick_start_001.png

pitch封装了matplotlib中pyplot的许多画图操作,可以一对一使用。

案例:射门数据分析

将前面的东西综合起来,我们可以得到一个表达出一场比赛中射门位置、射门xG(Expected Goals)的射门分析图

# 导入比赛数据 import pandas as pd import os from kloppy import statsbomb # 指定比赛id。如果想分析指定的赛事,可以写代码从分析competitions.json开始 match_id = 68366 # 指定数据位置。这里假定数据下载到了本机 base_url = /location/to/your/data/statsbomb/data # 加载数据并设定kloppy坐标系统,长宽坐标为0~1 # 注意有些未经转换的statsbomb附加数据的单位仍然是yard dataset = statsbomb.load( event_data=os.path.join(base_url, events/%s.json%match_id), lineup_data=os.path.join(base_url, lineups/%s.json%match_id), coordinates=kloppy ) # 从数据集中过滤出射门事件 shots = dataset.filter(shot) # 观察一下数据的元数据,包含了球场大小、进攻方向和坐标系统 print(dataset.metadata.pitch_dimensions) print(dataset.metadata.orientation) print(dataset.metadata.coordinate_system) # 参赛的两只球队 (team1, team2) = dataset.metadata.teams print(team1.name, team2.name) # 米表示的标准球场大小 pitch_length=105 pitch_width=68 # 我们只分析一只球队,所以画半场图形更方便 from mplsoccer import VerticalPitch pitch = VerticalPitch(line_color=black, half = True, pitch_length=pitch_length, pitch_width=pitch_width) fig, ax = pitch.grid(grid_height=0.9, title_height=0.06, axis=False, endnote_height=0.04, title_space=0, endnote_space=0) # 将射门事件转换为DataFrame # 保留了参赛队名称、射门的球场坐标和期望进球xG df = shots.to_df( lambda e: {team: e.team.name}, coordinate*, lambda e: {statsbomb_xg: e.raw_event[shot][statsbomb_xg]} ) # 筛选出其中一只队伍,这场比赛是巴塞罗那 df = df.loc[df[team]==team1.name] # 将射门事件用点散点图画出来,xG用条带颜色表示,颜色越深进球可能性越高 # 坐标位于[0,1],还有按照球场长宽进行转换 pitch.scatter( df.coordinates_x*pitch_length, df.coordinates_y*pitch_width, alpha=1, s = 500, c=df.statsbomb_xg*100, cmap=Reds, ax=ax[pitch], edgecolors=black ) fig.suptitle(%s射门位置%team1.name, fontsize = 30) plt.show() # 由于mplsoccer是基于matplotlib, # 注意解决非Windows系统中matplotlib的中文乱码

效果如下:

以上。

扫描二维码推送至手机访问。

版权声明:本文由财神资讯-领先的体育资讯互动媒体转载发布,如需删除请联系。

本文链接:http://www.tengj.cn/?id=64401

“Soccermatics之一:使用python分析足球数据集” 的相关文章

足球国家队世界排名更新:国足稳居亚洲前十!葡萄牙领先阿根廷!

足球国家队世界排名更新:国足稳居亚洲前十!葡萄牙领先阿根廷!

  原创/氧气是个地铁      2月18日,国际足联更新了最新一期足球国家队世界排名。其中国家队老大阿扎尔在俱乐部逐渐变成皇马队史最差一档水货的比利时依旧稳居第一,世界杯冠军法国队排第二,被中国互联网戏称为“欧洲中国队”的英格兰排第三,C罗所在的葡萄牙进前五,而梅西所在的...

2-0!阿根廷世界杯首胜来了!梅西逆境中爆发,轰1球1助告慰老马

2-0!阿根廷世界杯首胜来了!梅西逆境中爆发,轰1球1助告慰老马

继遭遇1-2不敌沙特队的爆冷后,阿根廷队的出线形势岌岌可危,在这绝不能输的逆境之下,潘帕斯雄鹰10号成功站了出来。梅西上演传射建功,力助球队2-0取得首胜,用最好的方式告慰逝世两周年的马拉多纳! 首轮的爆冷输球,让原本被认为是夺冠热门的阿根廷队突然站在了悬崖边,第2轮如果...

竞彩足球投注6大技巧,老球迷+老彩民多年成果助你玩转竞足

竞彩足球投注6大技巧,老球迷+老彩民多年成果助你玩转竞足

随着五大联赛的开战,又到了彩民和球迷狂欢的季节,特别是竞彩足球彩票,吸引了各位彩民纷纷来投注。投注当然就会有投注的技巧,本文希财君为大家带来老球迷兼彩民总结的竞彩足球投注6大技巧。 (1)充分了解对阵球队 竞彩足球投注6大技巧最重要的一点便是要充分了解对阵球队的情...

硬球比分:足球直播即时比分的体育平台

硬球比分:足球直播即时比分的体育平台

硬球比分覆盖全球3800+不同地区足球赛事视频信号源。为广大足球爱好者提供高清的视频直播、丰厚的福利活动、高阶的AI赛事决策模型、强大的专家团队、精准的赛事数据、无延的即时比分、劲爽的动画直播、资深的情报资讯等服务。 为什么选择我们? 【新人礼包】588元新人礼包...

早期足球比赛没有点球大战的规则,两队平局时怎么办?蚂蚁庄园11.26答案

早期足球比赛没有点球大战的规则,两队平局时怎么办?蚂蚁庄园11.26答案

  支付宝中蚂蚁庄园玩法11月26日小课堂的问题是早期足球比赛没有点球大战的规则,两队平局时曾经?答对即可获得一份180g小鸡宝宝饲料作为奖励。那么接下来就让我们一起了解一下11月26日蚂蚁庄园的正确答案吧! 蚂蚁庄园今日答题11月26日   1.早期足球比赛没有点球大战的...

给大家科普一下免费的足球推荐平台(2022已更新(今日/知乎)

给大家科普一下免费的足球推荐平台(2022已更新(今日/知乎)

U20世界杯十月 31日 大家晚上好,昨天公众号上推荐的比赛成功拿下连红,同时晚场微信上推荐的比赛也是稳稳拿下连红,今晚继续分享两场比赛,稳定状态今晚继续双红。 注:智多星不管成绩如何,哪怕红到爆炸或者黑成翔,成绩永远是为大家真实公开的!智多星做不到每场必...