分析 F1 统计数据 - 第一部分
分析 F1 统计数据 - 第一部分
介绍完 Ergast 数据集的使用方法之后,就到了分析的时候了!
Photo by author
在里面 上一篇文章 这 F1Stats
类被引入作为一种方便的方法来分析历史 F1 数据 厄加斯特 .所以现在是时候开始使用它了!
可能性几乎是无穷无尽的。下面的列表显示了一些可能的分析,它们是 github 上的 Jupyter Notebook .这个笔记本实现了 F1Stats
类和这些统计数据。粗体打印的统计数据在文章中进行了描述,其他的将在下一篇文章中介绍。留给读者的想象力来提出更有趣的分析。
- **历史
** - 驱动程序/构造函数的大多数胜利
- 最多连胜
- 冠军赢得的比赛数量,绝对和相对
- 拥有最多 DNF 的冠军
- 从未成为冠军的车手获得最多胜利
- 大多数杆位和杆位+获胜
- 每个赛季车手的平均年龄
- 最占主导地位的季节
- 2020 年大多数圈数领先
- **当前司机的经验
** - 赛道上的最后 10 名获胜者- 季节性
- 一轮后的WDC积分榜
- 将当前积分与上一季进行比较
- 每个车手的平均完成位置 - 两位车手的头对头统计数据
- 在过去 6 场比赛中得分- 种族
- 比赛中获得或失去的名额
- 比较两位车手的单圈时间
- 比赛期间的圈速表
使用辅助方法扩展基类
在深入研究数字之前,是时候完成 F1Stats 类并完成所有辅助方法了:
所以添加了以下方法:
- get_winners() - 通过过滤位置 equls 1 上的比赛结果返回所有大奖赛获胜者。
- get_quali_results() — 返回所有资格的结果,与上一篇文章中的 get_race_results() 逻辑相同
- get_pole_sitters() — 通过过滤位置等于 1 的资格结果返回极点位置。
- get_dnfs() — 返回所有未完成比赛的车手。在这种情况下,文本字段“positionText”不包含数字。
- get_wcc_standing() — 返回世界冠军赛每场比赛后的排名
- get_wdc_champions() — 返回所有车手世界冠军。首先找到所有最后一轮,然后将这些最后一轮在排名中的位置等于“1”。还计算该赛季赢得比赛的次数。
- get_laps_for_race() — 获取特定比赛的所有圈数。比赛由年份和轮数或赛事名称来识别。
获胜次数最多的车手
哪些车手在他们的职业生涯中赢得了最多的大奖赛?
职业生涯获胜次数最多的车手是刘易斯·汉密尔顿。在前 10 名中,有 4 名车手仍处于活跃状态。他们是汉密尔顿、维特尔、阿隆索和维斯塔潘。
Drivers with the most wins (image by author)
当我们查看制造商时,明显的赢家是法拉利。
Most wins per constructor (image by author)
从未成为世界冠军的获胜次数最多的车手
并非所有比赛都由世界冠军赢得。但是谁赢得了必须的比赛却没有成为世界冠军呢?这个比较难计算:
首先,我们确定所有大奖赛的最后一位获胜者。这相当于上一章。下一步是过滤掉世界冠军。这 冠军
变量包含 司机ID
适用于所有获得世界冠军的车手(第 5 行)。获奖者列表是针对此列表的过滤器。这 .isin()
函数返回 True 如果 司机ID
在世界冠军名单中。由于我们要过滤掉它们,所以比较的结果会被 ' 反转 ~
'。结果列表与驱动程序信息合并以添加驱动程序的名称(和其他信息)。
Drivers with most wins but no championship (image by author)
历年平均司机年龄
一级方程式车手越来越年轻。最年轻的车手是 MaxVerstappen (17y166d) 和 Lance Stroll (18y148d)。近年来,规则发生了变化,参加 F1 比赛的最低年龄要求为 18 岁。但是老司机们在哪里过去呢?让我们来了解一下。
数据框 比赛
有每个事件的日期和数据框 司机
有每个司机的出生日期。数据框 结果
将比赛与车手联系起来,因此通过将结果与车手和比赛合并,我们可以为每场比赛中的每位车手获得一排车手的出生日期和比赛日期。年龄是这两者的差值,但以纳秒表示,需要转换为年。
当我们添加了列 年龄
对于数据框,它每年分组,并计算所有年龄段的平均值。结果数据绘制在图表中。
Average driver age per year (image by author)
该图显示,与当前时代相比,早期的驾驶员年龄要大得多。 2014 年是最年轻的车手(27.3 岁),但从那时起年龄正在缓慢增加。随着一些老司机的退休,这个数字将再次下降。
查看每十年的平均年龄(在 通过...分组
功能)
df.groupby((df['year']//10)*10).mean()[['age']].round(1)
我们得到:
Average driver age per decade (image by author)
平均年龄下降了近 8 岁,并且在过去 20 年中似乎趋于稳定。由于最低年龄,它很可能会保持在这个水平。
当前领域的经验如何?
但是当前领域的经验如何?如果我们将经验转化为所驾驶的比赛数量,这可以从数据中确定。首先,我们必须确定当前赛季的驱动程序(第 2 行)。下一步(第 4 行)是过滤所有结果的列表 司机ID
.
在第 5 行 通过...分组
用于计算结果中每个驱动程序的出现次数。这会生成一个包含车手 ID、车手姓名和参加比赛次数的表格。臭名昭著的 水平条形图
用于可视化结果。请注意,该方法已移至 F1Stats
班级。
Experience of the current F1 field (image by author)
换个角度看,所有参加过F1比赛的车手的平均比赛次数是30场。在目前的赛场上,只有周冠宇的比赛次数较少。今天的赛季比过去包含更多的比赛,但车手的比赛年限比以往任何时候都多。
WDC 赛季排名
是时候抛开历史的洞见,看看当前的季节了。首先,让我们看看车手在赛季中的排名是如何变化的。
由于引入了辅助函数,这很容易。我们获得一个季节的 wdc 结果。该数据框包含车手、回合数以及每位车手在每一回合后的冠军积分。这已经是我们概述所需的所有信息。
Championship standings (image by author)
该图显示了每位车手在锦标赛中的位置。它没有深入了解驱动程序之间的点差。通过替换' 位置'
和 ' 积分
' 在第 4 行,将绘制每个驱动程序的点:
Championship points during the season (image by author)
它使图表的底部杂乱无章,但可以深入了解勒克莱尔和佩雷斯之间以及罗素和塞恩斯之间的近距离战斗,尽管汉密尔顿正在接近他们。
将当前积分与上一季进行比较
今年,F1 的排名发生了很大变化。法拉利似乎重回榜首,梅赛德斯有点落后。但像迈凯轮和阿尔法金牛这样的车队似乎表现不佳。
正如在这样的文章中所预期的那样,让我们深入研究这些数字。我们想知道与去年相比,一支球队的表现如何。我们最好的指标是与去年同期相比,球队今年获得的积分数,例如今年 13 轮。
首先,确定当前积分(第 3-5 行),从而选择该轮作为最后一轮比赛(此时是匈牙利大奖赛,第 13 轮)。接下来,确定赛季中同一时刻(比赛回合)的积分数(第 7-9 行)。第 3-5 行和第 7-9 行之间的唯一区别是年份。
合并这两年的结果数据(第 11 行)并计算两年之间的点差(第 12 行)。第 13-14 行确定颜色,绿色为正,红色为负差。情节最终在第 16-27 行制作,包括带有标签的布局等。
Points difference compared to last year (image by author)
与去年相比,红牛和法拉利的表现都要好得多。令人惊讶的是,梅赛德斯并不是积分挫折最大的球队。这一荣誉属于 McLaren en AlphaTauri。梅赛德斯和红牛之间的差距比去年大了 140 分,但主要是因为红牛表现更好。法拉利几乎超出了规模,但由于去年的糟糕表现并没有将它们带到排行榜的首位。
两名司机并肩作战
比较队友的常用可视化是头对头。两位车手在排位赛和比赛统计数据上以一对一的方式进行比较。例如,使用的统计数据是在队友面前完成的比赛、在队友面前获得资格、得分、本赛季登上领奖台的次数和比赛获胜次数。如果两位车手不争夺领奖台名额,通常采用最佳完赛名次和最佳资格名次。
Driver comparison (image by author)
所以这将需要一些代码来计算统计信息:
第一步是定义年份,定义驱动程序(通过缩写)并检索 驱动程序 ID
的(第 1-7 行)。第 9-17 行计算比赛结果统计数据。循环遍历所选赛季中的所有比赛。为每个车手确定终点位置。如果司机 1 在司机 2 之前完成,他的计数器会增加,反之亦然。如果他们的完赛位置相同,则他们都没有完成比赛,因此不增加计数器。
计数器数组有第三个字段,预填充值 10。该值用于绘图,将在此处进行说明。
第 19 到 20 行执行相同的逻辑,但用于限定结果。第 29 到 32 行计算到目前为止的得分。首先确定本赛季最后一轮的成绩,然后存储本轮后两位车手的积分。
对于获胜者,获胜者的数据框将在驱动程序和完成位置“1”上进行过滤。结果数据帧的长度是车手赢得比赛的次数。当过滤更改为等于或小于 3 时,计算领奖台完成次数。
现在我们有了所有的个人计数,可以创建比较两个驱动程序的图表
比较图由第一个驱动程序的左侧条和第二个驱动程序的右侧条构建。这是通过将第一个驱动程序的值绘制为负值而将第二个驱动程序的值绘制为正值来完成的。通过根据相同的 y 值绘制条形图,它们出现在相同的高度上。
通过将值除以行上的最大值,将每行缩放到最大值 1。这确保了所有行都是可见的,并且不会被例如得分推到视线之外。这是前面提到的 10 的数量。它确保低于 10 的数字不是相对于其最大值的比例,而是比例为 10 的值。因此,如果两位车手都赢得了 1 场比赛,则绘制的条形图为最大宽度的 1/10。它使图表更容易在视觉上消费。
首先,准备好具有 y 值、x 值、标签和颜色的数组。颜色是驱动程序 1 的颜色的重复,然后是驱动程序 2,然后是驱动程序 1。等等。numpy 瓦
函数用于指定两种颜色的重复。然后在第 16 行绘制矩形。 plot 命令将创建的数组作为 (x,y) 值的输入和要绘制的颜色。
第 21-24 行通过设置 x 轴宽度,在“0”值处绘制一条垂直线,从而划分两个驱动程序并删除图形的边界框 (22-25),对图形进行布局。第 26 行删除了 x 轴上的刻度,因为它们不代表实际值。
比赛中获得或失去的名额
在比赛级别上,有趣的概述之一是在比赛中获得和失去的地方。
首先,我们按年份和年份过滤结果结果。过滤年份在 get_race_results()
方法,按轮次过滤需要单独完成(尽管可以添加到 get_results 方法中)。在这一步中,数据帧的列也被减少到所需的子集(第 4 行)。
生成的数据帧已经包含开始和结束位置,因此通过计算这两者之间的差异很容易计算获得或丢失的位置数。
由于我们使用的是 Jupyter Notebook,因此可以向数据框添加显示样式(第 10 行)。在这种情况下,我们添加一个显示样式 ( color_red_or_green
) 到列 改变
根据正值或负值更改背景颜色。这导致:
Places gained and lost(image by author)
不需要额外的排序,因为 get_race_result
方法已经按位置排序。
结论
在上一篇文章中的数据准备之后,开始分析数据并收集新的见解相对简单。本笔记本描述了一些示例和 Jupyter 笔记本 更。但极限是由你自己的想象决定的!
正如在上一篇文章中已经提到的,花在数据准备上的时间是值得的。它减少了本文要做的工作量。互联网上充满了数据,经过一些认真的努力,可用性很好。
最后的话
我希望你喜欢这篇文章。如需更多灵感,请查看我的其他一些文章:
- F1 分析和 Python 入门
- F1匈牙利:一些观察
- 使用 Python 和“scikit-learn”进行燃料价格预测
- 太阳能电池板发电分析
- 对 CSV 文件中的列执行函数
- 从您的活动跟踪器的日志中创建热图
- 使用 Python 的并行 Web 请求
如果你喜欢这个故事,请点击关注按钮!
免责声明:本文中包含的观点和意见仅属于作者。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明