Pandas请你吃英超联赛积分榜上没有的瓜!
点击上方关注,All in AI中国
18-19赛季英超联赛冠军争夺赛即将到来,在接下来的几场比赛中,冠军候选席位争夺日益激烈。最终冠军将花落谁家呢?
接下来,让我们用Python pandas来解析英超联赛表,并展示如何开始使用Python进行一些积分榜中没有的探索性分析。
网页数据抓取
pandas有一个内置函数read_html(),它使用库lxml和Beautiful Soup自动将HTML文件中的数据解析为数据框对象。首先,需要安装read_html()使用的一些附加库。在终端输入:
pip install lxml pip install beautifulsoup4 html5lib
pandas read_html函数有许多自定义选项,但默认情况下它会搜索并尝试解析<table>标记中包含的所有表格数据,这会生成一个数据框对象列表。
导入pandas库,使用read_html函数来解析Premier League Table,将其分配给变量prem_table。我们采用的第一个元素,时间是英超联赛表中截至20/04/19英国夏令时22:00。大多数人的焦点都集中在前4名的争夺上,所以我们来使用.head()方法可视化这个表中的前6个条目。为了保证准确,使用shape属性并显示出一共有21行、12列。这个操作是有必要的,因为Python是从0开始计算行数的,我们知道英超共有20支英超球队,因此数据其实是多一行的。可以看出,数据框开头部分是没有问题的,所以有问题的是应该是数据框末尾数据。
import pandas as pd prem_table = pd.read_html('https://www.bbc.co.uk/sport/football/premier-league/table') Premier_table = prem_table[0] print(len(prem_table)) print(type(prem_table)) print(Premier_table.head(6)) # Output 1 <class 'list'>
由于任务是对数据进行探索性分析,所以我最初想“清理”数据。但是看起来没必要在数据框中使用“Unnamed: 1”列。 我们使用drop方法,删除列,传入关键字参数“axis = 1”进行逐列删除。
Premier_table.columns Index(['Unnamed: 0', 'Unnamed: 1', 'Team', 'P', 'W', 'D', 'L', 'F', 'A', 'GD', 'Pts', 'Form'], dtype='object') Premier_league = Premier_table.drop(['Unnamed: 1'], axis=1) Premier_league.head(6)
数据框中的数据类型
数据框中的每一列都可以被认为是一个系列,其中每列必须属于同一类型。 但是,每行可以是不同类型的。由于我们需要分析数据,所以需要解读每个系列的数据类型。“Team”列很明显是Python字符串。此外,目测希望表示游戏数量的“P”列是一个Python浮点数或整型数。但是猜想归猜想,最好还是使用dtypes属性或info方法进行确认。
此输出内容显示,系列的dtypes是“objects”,即Python字符串。我们必须更改这些类型才能在不同列之间执行数值计算。 当然,这只是Python中的一项简单任务,我们只需使用pandas to_numeric方法。 pandas.to_numeric()是Pandas中的一般函数,用于将参数转换为数字类型。 在这里,我们将想要分析的列更改为panda float (float64)数据类型。为了确认结果,检查数据框dtypes:
清理数据框
shape属性显示输入的列数太多,这是因为我们的假设是20支球队都在竞争冠军 。通过前面的步骤我们知道数据框的开头没有问题,所以问题多半出现在末尾。
很明显,有一些不必要的元数据以及填充列的一些NaN(不是数字条目)。同样的,再次使用drop方法,只是这次要省略“axis = 1”参数。 这样问题就解决了,还可以使用shape属性验证此行是否已成功删除。
Table.drop(Table.tail(1).index, inplace=True) Table.tail(3) Table.shape # Output (20, 12)
现在看起来好像没什么问题了,但球队的联赛排名栏标题为“Unnamed: 0”,这似乎有些奇怪,它不能代表列的内容。要更改这一点可以使Pandas Dataframe.rename() 方法,并传入inplace = True,如果为True,它将更改原始数据框信息。
Table.columns Index(['Unnamed: 0', 'Team', 'P', 'W', 'D', 'L', 'F', 'A', 'GD', 'Pts', 'Form'], dtype='object') Table.rename(columns={'Unnamed: 0':'Position'}, inplace=True) Table.head()
创建新列
数据框已经设置好了,此时,创建一些新列并测试前面创建的“string-to-float”转换是否有效。
创建名为“进球比率”的新栏,这个数字是总射门数除以进球数。创建一个新列,输入的数据框的名称,然后使用方括号符号,并在引号中输入新列标题。在等式的右边,使用相同的技术从表数据框中选择想要的列。在这里,我们将每一列' F '项与每一列' A '项相除,并四舍五入到小数点后一位。默认情况下,创建的每个新列都附加到数据框的末尾。
将列重新排列,只需更改列条目的顺序并将它们添加到列表中,然后将其重新分配给表数据框,删除“Form”列,使表更整洁。
过滤数据框
这张表设置得很适合分析,我们先尝试分析一个简单的问题:哪些球队比对手少打了一场比赛?由于每支球队都打了34场或35场比赛,所以我只对打了34场比赛的球队进行筛选(截至19年4月20日),结果就会显示出来。为了过滤,我使用了布尔索引。要了解如何做到这一点,请阅读我关于“如何通过列值过滤panda数据框的行”的文章。
接下来,让我们来看看谁的抽签次数最多。
南安普顿试图避免本赛季的下滑趋势,所有的平局都会有哪些代价呢?
最后,让我们创建两个新列,“Goals/game”和“Goal conceded/game”,并使用sort_values方法对数值进行排序。
Table['Goals/game'] = round((Table.F / Table.P), 1) Table['Goals conceded/game'] = round((Table['A'] / Table['P']), 1) Table.sort_values(['Goals/game', 'Goal Ratio']).head(5)
哈德斯菲尔德和富勒姆已经受到了谴责,卡迪夫的入球率排名第三,失球率排名第二。与降级对手布莱顿相比,他们的进球差距也最大。
加得夫的情况更糟,他们能从下跌中幸存下来吗?他们的新兵没有足够的威胁,他们的防守是不是太脆弱了?
本文已经展示了pandas的一些特性,这些特性有助于使用pandas进行数据分析。有 Python Pandas,我们就能寻找这些问题的答案了!
编译出品