利用Pandas进行数据分析
利用 Pandas 进行数据分析
原文:https://www.dataquest.io/blog/pandas-python-tutorial/
作者:Vik Paruchuri
译者:linkcheng
Python 是进行数据分析的绝佳语言,主要原因是以数据为中心的 Python 包的奇妙生态系统。Pandas 就是其中之一,它使得导入和分析数据更容易。
Pandas 以 NumPy 和 matplotlib 包为底层驱动,为您提供更方便的接口用来完成大多数数据分析和可视化工作。
在这篇教程中,我们将使用 Pandas 来分析 IGN(一个热门的视频游戏评论网站)的视频游戏评论数据。
数据收集在 Eric Grinstein ,可以在https://www.kaggle.com/egrinstein/20-years-of-games找到。
在我们分析视频游戏评论的过程,将学习 Pandas 关键的概念,例如索引等。
像 “巫师 3” 这样的游戏在 PS4 上会比在 Xbox One 上获得更好的评价吗? 这个数据集可以帮助我们找出答案。
首先声明,以下我们将使用 Python 3.5 和 Jupyter Notebook 来进行分析。
译者注:brew install python3; pip3 install jupyter; pip3 install pandas (MacOS)。 jupyter教程:http://codingpy.com/article/getting-started-with-jupyter-notebook-part-1/
使用 pandas 导入数据
我们将采取的第一步是读取数据。数据存储为用逗号分隔类型的文件,如 csv 文件,它们一行代表一条记录,列与列之间用逗号(,
)分开
。 下面是 ign.csv
文件的前几行:
,score_phrase,title,url,platform,score,genre,editors_choice,release_year,release_month,release_day 0,Amazing,LittleBigPlanet PS Vita,/games/littlebigplanet-vita/vita-98907,PlayStation Vita,9.0,Platformer,Y,2012,9,12 1,Amazing,LittleBigPlanet PS Vita -- Marvel Super Hero Edition,/games/littlebigplanet-ps-vita-marvel-super-hero-edition/vita-20027059,PlayStation Vita,9.0,Platformer,Y,2012,9,12 2,Great,Splice: Tree of Life,/games/splice/ipad-141070,iPad,8.5,Puzzle,N,2012,9,12 3,Great,NHL 13,/games/nhl-13/xbox-360-128182,Xbox 360,8.5,Sports,N,2012,9,11
如上所示,数据中的每一行代表一个由 IGN 发行的游戏。 列包含有关该游戏的信息:
- score_phrase - IGN 用一个词描述该游戏。 这与得到的分数相关联。
- title - 游戏的名称。
- url - 可以在其中查看完整评价的网址。
- platform - 游戏评论的平台(PC,PS4等)。
- score - 游戏的分数,从1.0到10.0。
- genre - 游戏的类型。
- editors_choice -
N
代表游戏不是编辑的选择,Y
代表是。 这与得分相关。 - release_year - 游戏发布的年份。
- release_month - 游戏发布的月份。
- release_day - 游戏发布的天。
还有一个包含行索引值的引导列。现在我们可以忽略此列,但随后我们将深入索引值的意义。
为了能够使用 Python中 的数据,我们需要将 csv 文件读入 Pandas DataFrame。 DataFrame (数据帧)是一种表示和处理表格数据的方法。表格数据具有行和列,就像我们的 csv 文件一样。
为了读入数据,我们需要使用 pandas.read_csv 函数。 此函数将接收一个 csv 文件并返回一个 DataFrame。
下面的代码将:
- 导入
pandas
库。 我们将它重命名为pd
,这样后续写起来更方便。 - 把
ign.csv
文件内容读到 DataFrame 中,并将它起名字叫review
。
import pandas as pd reviews = pd.read_csv("ign.csv")
把数据读入到 DataFrame 后,Pandas 提供两个方法让我们快速打印出数据。
这两个函数是:
- pandas.DataFrame.head - 打印 DataFrame 的第 N 行。默认值 5。
- pandas.DataFrame.tail - 打印 DataFrame 的最后 N 行。默认值 5。
我们用 head
方法看下 review
中到底是些什么:
reviews.head()
Unnamed: 0 | score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | Amazing | LittleBigPlanet PS Vita | /games/littlebigplanet-vita/vita-98907 | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
1 | 1 | Amazing | LittleBigPlanet PS Vita -- Marvel Super Hero E... | /games/littlebigplanet-ps-vita-marvel-super-he... | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
2 | 2 | Great | Splice: Tree of Life | /games/splice/ipad-141070 | iPad | 8.5 | Puzzle | N | 2012 | 9 | 12 |
3 | 3 | Great | NHL 13 | /games/nhl-13/xbox-360-128182 | Xbox 360 | 8.5 | Sports | N | 2012 | 9 | 11 |
4 | 4 | Great | NHL 13 | /games/nhl-13/ps3-128181 | PlayStation 3 | 8.5 | Sports | N | 2012 | 9 | 11 |
我们还可以通过 pandas.DataFrame.shape 属性查看 reviews
有多少行列:
reviews.shape
(18625,11)
如上所示,一切都已正确读取,我们有 18625 行 11 列。
在 Pandas vs NumPy 中,Pandas 的一个很大的优点是允许你有不同数据类型的列。 reviews
具有
float 类型的列,如 score
,string 类型,如 score_phrase
和
integer 类型,如 release_year。
现在我们已经正确读取了数据,让我们从 reviews
中检索我们想要的行和列。
使用 Pandas 进行 DataFrame(数据帧)检索
之前,我们使用 head
方法打印前 5
行的 reviews
。
我们可以使用 pandas.DataFrame.iloc 方法完成同样的事情。
iloc
方法允许我们按位置检索行和列。 为了做到这一点,我们需要指定我们想要的行的位置,以及我们想要的列的位置。
以下代码与 reviews.head(5)
效果相同:
reviews.iloc[0:5,:]
Unnamed: 0 | score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | Amazing | LittleBigPlanet PS Vita | /games/littlebigplanet-vita/vita-98907 | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
1 | 1 | Amazing | LittleBigPlanet PS Vita -- Marvel Super Hero E... | /games/littlebigplanet-ps-vita-marvel-super-he... | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
2 | 2 | Great | Splice: Tree of Life | /games/splice/ipad-141070 | iPad | 8.5 | Puzzle | N | 2012 | 9 | 12 |
3 | 3 | Great | NHL 13 | /games/nhl-13/xbox-360-128182 | Xbox 360 | 8.5 | Sports | N | 2012 | 9 | 11 |
4 | 4 | Great | NHL 13 | /games/nhl-13/ps3-128181 | PlayStation 3 | 8.5 | Sports | N | 2012 | 9 | 11 |
正如你看到的那样,我们指定了我们想要的行 0:5
。 这意味着我们取 0 到
5 行的数据,但不包括第 5 行。第一行被认为是在位置 0。这时我们获取了第 0,1,2,3
和 4
行的数据。
如果我们缺失第一个位置的值,如:5
,这个地方的默认值就是 0 。如果我们缺失最后一个位置额值,如 0
:
,它默认到 DataFrame 中的最后一行或列。
我们想要所有的列,所以我们只指定一个冒号(:),没有任何位置。 这给了我们从0到最后一列的列。
以下是一些关于索引使用的例子,以及对结果的解释:
-
reviews.iloc[:5,:]
– 前5
行, 及其全部列数据。 -
reviews.iloc[:,:]
– 所有行所有列的数据。 -
reviews.iloc[5:,5:]
– 从第5
行开始到最后一行, 及第5
列开始到最后一列的数据。 -
reviews.iloc[:,0]
– 所有行的第一列数据。 -
reviews.iloc[9,:]
– 第十行的所有列数据。
这种使用索引的方法与 NumPy 的索引用起来很类似。如果你想详细了解,点击这里可以获取更多关于 Numpy 的教程。
现在我们知道了怎么通过位置来检索数据,那么让我们除去无用的第一列信息。
reviews = reviews.iloc[:,1:] reviews.head()
score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Amazing | LittleBigPlanet PS Vita | /games/littlebigplanet-vita/vita-98907 | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
1 | Amazing | LittleBigPlanet PS Vita -- Marvel Super Hero E... | /games/littlebigplanet-ps-vita-marvel-super-he... | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
2 | Great | Splice: Tree of Life | /games/splice/ipad-141070 | iPad | 8.5 | Puzzle | N | 2012 | 9 | 12 |
3 | Great | NHL 13 | /games/nhl-13/xbox-360-128182 | Xbox 360 | 8.5 | Sports | N | 2012 | 9 | 11 |
4 | Great | NHL 13 | /games/nhl-13/ps3-128181 | PlayStation 3 | 8.5 | Sports | N | 2012 | 9 | 11 |
使用 Pandas 中的标签检索
现在我们知道如何按位置检索行和列,而通过标签检索行和列是另一种值得研究的使用数据帧的方式。
Pandas 比 NumPy 的主要优点是每一列和行都有一个标签。 尽管使用列位置也可以做一些操作,但却很难跟踪哪个数字对应于哪个列。
我们可以使用 pandas.DataFrame.loc 方法处理标签,它允许我们使用标签而不是位置进行索引。
我们可以使用 loc
方法显示前五行 reviews
,如下所示:
reviews.loc[0:5,:]
score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Amazing | LittleBigPlanet PS Vita | /games/littlebigplanet-vita/vita-98907 | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
1 | Amazing | LittleBigPlanet PS Vita -- Marvel Super Hero E... | /games/littlebigplanet-ps-vita-marvel-super-he... | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
2 | Great | Splice: Tree of Life | /games/splice/ipad-141070 | iPad | 8.5 | Puzzle | N | 2012 | 9 | 12 |
3 | Great | NHL 13 | /games/nhl-13/xbox-360-128182 | Xbox 360 | 8.5 | Sports | N | 2012 | 9 | 11 |
4 | Great | NHL 13 | /games/nhl-13/ps3-128181 | PlayStation 3 | 8.5 | Sports | N | 2012 | 9 | 11 |
5 | Good | Total War Battles: Shogun | /games/total-war-battles-shogun/mac-142565 | Macintosh | 7.0 | Strategy | N | 2012 | 9 | 11 |
以上结果与 reviews.iloc[0:5,:]
的结果并没有太大不同。这是因为行标签可以使用任意类型的值,使得行标签是准确匹配位置。你可以在上面的表格的左侧看到行标签(加粗部分)。当然也可以通过访问数据帧的 index 属性,以下将会展示 reviews
的行索引属性:
reviews.index
Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...], dtype='int64')
不过索引并不总是与位置匹配。 在下面的代码块中,我们将:
- 获取第
10
行到第20
行的reviews
,并且赋值给some_reviews
。 - 展示
some_reviews
的前5
行内容。
some_reviews = reviews.iloc[10:20,] some_reviews.head()
如上所示,some_reviews
的索引是从 10
到 20
。这样以来,尝试给loc
出入小于 10
或者大于 20
的值时,就会有以下错误:
some_reviews.loc[9:21,:]
score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|
10 | Good | Tekken Tag Tournament 2 | /games/tekken-tag-tournament-2/ps3-124584 | PlayStation 3 | 7.5 | Fighting | N | 2012 | 9 | 11 |
11 | Good | Tekken Tag Tournament 2 | /games/tekken-tag-tournament-2/xbox-360-124581 | Xbox 360 | 7.5 | Fighting | N | 2012 | 9 | 11 |
12 | Good | Wild Blood | /games/wild-blood/iphone-139363 | iPhone | 7.0 | NaN | N | 2012 | 9 | 10 |
13 | Amazing | Mark of the Ninja | /games/mark-of-the-ninja-135615/xbox-360-129276 | Xbox 360 | 9.0 | Action, Adventure | Y | 2012 | 9 | 7 |
14 | Amazing | Mark of the Ninja | /games/mark-of-the-ninja-135615/pc-143761 | PC | 9.0 | Action, Adventure | Y | 2012 | 9 | 7 |
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-76-5378b774c9a7> in <module>() ----> 1 some_reviews.loc[9:21,:] # 省略了许多内容 /Users/vik/python_envs/dsserver/lib/python3.4/site-packages/pandas/core/indexing.py in _has_valid_type(self, key, axis) 1258 raise KeyError( 1259 "start bound [%s] is not the [%s]" % -> 1260 (key.start, self.obj._get_axis_name(axis)) 1261 ) 1262 if key.stop is not None: KeyError: 'start bound [9] is not the [index]'
译者注:在本地运行 some_reviews.loc[9:21,:] 时并不报错,而是以下信息,这可能与版本有关。
正如我们前面提到的,处理数据时,使用列标签操作起来更方便。 我们可以在 loc
方法中指定列标签,按标签名检索列而不是按位置检索列。
reviews.loc[:5, "score"]
0 9.0 1 9.0 2 8.5 3 8.5 4 8.5 5 7.0 Name: score, dtype: float64
我们也可以通过列表的方式一次列举多列数据。
reviews.loc[:5, ["score", "release_year"]]
score | release_year | |
---|---|---|
0 | 9.0 | 2012 |
1 | 9.0 | 2012 |
2 | 8.5 | 2012 |
3 | 8.5 | 2012 |
4 | 8.5 | 2012 |
5 | 7.0 | 2012 |
Pandas Series(序列)对象
我们可以通过 Pandas 不同方法来检索一个单个列。到目前为止,我们已经两种类型的语法:
-
reviews.iloc[:,1]
- 检索第二列 -
reviews.loc[:," core_phrase"]
- 同样也是第二列
还有第三种,甚至更容易的方式检索整个列。 我们可以在方括号中指定列名,就像字典一样:
reviews["score"]
0 9.0 1 9.0 2 8.5 3 8.5 4 8.5 5 7.0 6 3.0 7 9.0 8 3.0 9 7.0 10 7.5 11 7.5 12 7.0 13 9.0 14 9.0 15 6.5 16 6.5 17 8.0 18 5.5 19 7.0 20 7.0 21 7.5 22 7.5 23 7.5 24 9.0 25 7.0 26 9.0 27 7.5 28 8.0 29 6.5 ... 18595 4.4 18596 6.5 18597 4.9 18598 6.8 18599 7.0 18600 7.4 18601 7.4 18602 7.4 18603 7.8 18604 8.6 18605 6.0 18606 6.4 18607 7.0 18608 5.4 18609 8.0 18610 6.0 18611 5.8 18612 7.8 18613 8.0 18614 9.2 18615 9.2 18616 7.5 18617 8.4 18618 9.1 18619 7.9 18620 7.6 18621 9.0 18622 5.8 18623 10.0 18624 10.0 Name: score, dtype: float64
我们依然可以使用列表的方式:
reviews[["score", "release_year"]]
score | release_year | |
---|---|---|
0 | 9.0 | 2012 |
1 | 9.0 | 2012 |
2 | 8.5 | 2012 |
3 | 8.5 | 2012 |
4 | 8.5 | 2012 |
5 | 7.0 | 2012 |
6 | 3.0 | 2012 |
7 | 9.0 | 2012 |
8 | 3.0 | 2012 |
9 | 7.0 | 2012 |
10 | 7.5 | 2012 |
11 | 7.5 | 2012 |
12 | 7.0 | 2012 |
13 | 9.0 | 2012 |
14 | 9.0 | 2012 |
15 | 6.5 | 2012 |
16 | 6.5 | 2012 |
17 | 8.0 | 2012 |
18 | 5.5 | 2012 |
19 | 7.0 | 2012 |
20 | 7.0 | 2012 |
21 | 7.5 | 2012 |
22 | 7.5 | 2012 |
23 | 7.5 | 2012 |
24 | 9.0 | 2012 |
25 | 7.0 | 2012 |
26 | 9.0 | 2012 |
27 | 7.5 | 2012 |
28 | 8.0 | 2012 |
29 | 6.5 | 2012 |
... | ... | ... |
18595 | 4.4 | 2016 |
18596 | 6.5 | 2016 |
18597 | 4.9 | 2016 |
18598 | 6.8 | 2016 |
18599 | 7.0 | 2016 |
18600 | 7.4 | 2016 |
18601 | 7.4 | 2016 |
18602 | 7.4 | 2016 |
18603 | 7.8 | 2016 |
18604 | 8.6 | 2016 |
18605 | 6.0 | 2016 |
18606 | 6.4 | 2016 |
18607 | 7.0 | 2016 |
18608 | 5.4 | 2016 |
18609 | 8.0 | 2016 |
18610 | 6.0 | 2016 |
18611 | 5.8 | 2016 |
18612 | 7.8 | 2016 |
18613 | 8.0 | 2016 |
18614 | 9.2 | 2016 |
18615 | 9.2 | 2016 |
18616 | 7.5 | 2016 |
18617 | 8.4 | 2016 |
18618 | 9.1 | 2016 |
18619 | 7.9 | 2016 |
18620 | 7.6 | 2016 |
18621 | 9.0 | 2016 |
18622 | 5.8 | 2016 |
18623 | 10.0 | 2016 |
18624 | 10.0 | 2016 |
18625 rows × 2 columns
当我们检索单个列时,我们实际上检索了一个 Pandas Series 对象。 DataFrame 存储表格数据,但是 Series 存储单个数据列或行。
我们可以验证单个列是否为系列:
type(reviews["score"])
pandas.core.series.Series
我们可以手动创建一个 Series,以更好地了解它是如何工作的。 创建一个 Series,当我们实例化它时,我们需要将一个 list 类型或 NumPy 数组传递给 Series 对象:
s1 = pd.Series([1, 2]) s1
0 1 1 2 dtype: int64
Serise 可以包含任何类型的数据,包括混合类型。 在这里,我们创建一个包含字符串对象的 Serise:
s2 = pd.Series(["Boris Yeltsin", "Mikhail Gorbachev"]) s2
0 Boris Yeltsin 1 Mikhail Gorbachev dtype: object
通过 Pandas 创建 数据帧 DataFrame
我们可以通过将多个 Series 对象传递给 DataFrame 类来创建一个 DataFrame。 在这里,我们传入我们刚刚创建的两个 Series 对象,s1
作为第一行,s2
作为第二行:
pd.DataFrame([s1, s2])
0 | 1 | |
---|---|---|
0 | 1 | 2 |
1 | Boris Yeltsin | Mikhail Gorbachev |
我们也可以通过传递成员为列表的列表来完成同样的事情。 每个内部列表在结果 DataFrame 中被视为一行:
pd.DataFrame( [ [1,2], ["Boris Yeltsin", "Mikhail Gorbachev"] ] )
0 | 1 | |
---|---|---|
0 | 1 | 2 |
1 | Boris Yeltsin | Mikhail Gorbachev |
我们可以在创建 DataFrame 时指定列标签:
pd.DataFrame( [ [1,2], ["Boris Yeltsin", "Mikhail Gorbachev"] ], columns=["column1", "column2"] )
column1 | column2 | |
---|---|---|
0 | 1 | 2 |
1 | Boris Yeltsin | Mikhail Gorbachev |
同样可以指定行标签(即索引 index ):
frame = pd.DataFrame( [ [1, 2], ["Boris Yeltsin", "Mikhail Gorbachev"] ], index=["row1", "row2"], columns=["column1", "column2"] ) frame
column1 | column2 | |
---|---|---|
row1 | 1 | 2 |
row2 | Boris Yeltsin | Mikhail Gorbachev |
然后,我们可以使用以下标签对DataFrame建立索引:
frame.loc["row1":"row2", "column1"]
row1 1 row2 Boris Yeltsin Name: column1, dtype: object
如果我们将字典传递给 DataFrame 的构造函数,那么我们可以跳过指定 column
关键字参数。
这将会自动为列设置名称:
frame = pd.DataFrame( { "column1": [1, 2], "column2": ["Boris Yeltsin", "Mikhail Gorbachev"] } ) frame
column1 | column2 | |
---|---|---|
0 | 1 | Boris Yeltsin |
1 | 2 | Mikhail Gorbachev |
Pandas DataFrame 方法
正如之前我们提到的,DataFrame 的每一个列都是一个 Series 对象
type(reviews["title"])
pandas.core.series.Series
那些对 DataFrame 适用的方法大多同样也适用于 Series 对象,包括 head
:
reviews["title"].head()
0 LittleBigPlanet PS Vita 1 LittleBigPlanet PS Vita -- Marvel Super Hero E... 2 Splice: Tree of Life 3 NHL 13 4 NHL 13 Name: title, dtype: object
Pandas Series 和 DataFrames 中也有其他方法,使计算更简单。 例如,我们可以使用 pandas.Series.mean 方法来查找一个 Series 的平均值:
reviews['score'].mean()
6.950459060402685
我们也可以调用类似的 pandas.DataFrame.mean 方法,它将在默认情况下找到 DataFrame 中每个数字列的平均值:
reviews.mean()
score 6.950459 release_year 2006.515329 release_month 7.138470 release_day 15.603866 dtype: float64
我们可以通过给 mean
方法添加 axis
关键字参数,用来计算每行或者每列的平均值。axis
的缺省值为
0 ,并计算每一列的平均值。也可以设置为 1 来计算每一行的平均值。请注意,这只会计算每一行中类型为数值的平均值:
reviews.mean(axis=1)
0 510.500 1 510.500 2 510.375 3 510.125 4 510.125 5 509.750 6 508.750 7 510.250 8 508.750 9 509.750 10 509.875 11 509.875 12 509.500 13 509.250 14 509.250 15 508.375 16 508.375 17 508.500 18 507.375 19 507.750 20 507.750 21 514.625 22 514.625 23 514.625 24 515.000 25 514.250 26 514.750 27 514.125 28 514.250 29 513.625 ... 18595 510.850 18596 510.875 18597 510.225 18598 510.700 18599 510.750 18600 512.600 18601 512.600 18602 512.600 18603 512.450 18604 512.400 18605 511.500 18606 508.600 18607 510.750 18608 510.350 18609 510.750 18610 510.250 18611 508.700 18612 509.200 18613 508.000 18614 515.050 18615 515.050 18616 508.375 18617 508.600 18618 515.025 18619 514.725 18620 514.650 18621 515.000 18622 513.950 18623 515.000 18624 515.000 dtype: float64
在 Series 和 DataFrames 上有很多方法,它们的行为类似于 mean
。
这里有一些常见的:
- pandas.DataFrame.corr – 查找 DataFrame 中列之间的相关性。
- pandas.DataFrame.count – 计算每个 DataFrame 列中的非空值的数量。
- pandas.DataFrame.max – 查找每个列中的最大值。
- pandas.DataFrame.min – 查找每个列中的最小值。
- pandas.DataFrame.median – 查找每列的中位数。
- pandas.DataFrame.std – 查找每列的标准差。
我们可以使用 corr
方法来查看是否有任何列与 score 相关。 例如,通过这种方式我们可以得到,最近发布的游戏是否获得了更高的评价(release_year),或者是否年底发布的游戏得分更好(release_month):
reviews.corr()
score | release_year | release_month | release_day | |
---|---|---|---|---|
score | 1.000000 | 0.062716 | 0.007632 | 0.020079 |
release_year | 0.062716 | 1.000000 | -0.115515 | 0.016867 |
release_month | 0.007632 | -0.115515 | 1.000000 | -0.067964 |
release_day | 0.020079 | 0.016867 | -0.067964 | 1.000000 |
如上所述,我们的数字列都不与 score
相关,这意味着发布时间与审核分数没有线性关系。
Dataframe Math with Pandas
我们还可以对 Series 或 DataFrame 对象执行数学运算。 例如,我们可以将核心列中的每个值除以 2
,将比例从 0-10
切换到 0-5
:
reviews["score"] / 2
0 4.50 1 4.50 2 4.25 3 4.25 4 4.25 5 3.50 6 1.50 7 4.50 8 1.50 9 3.50 10 3.75 11 3.75 12 3.50 13 4.50 14 4.50 15 3.25 16 3.25 17 4.00 18 2.75 19 3.50 20 3.50 21 3.75 22 3.75 23 3.75 24 4.50 25 3.50 26 4.50 27 3.75 28 4.00 29 3.25 ... 18595 2.20 18596 3.25 18597 2.45 18598 3.40 18599 3.50 18600 3.70 18601 3.70 18602 3.70 18603 3.90 18604 4.30 18605 3.00 18606 3.20 18607 3.50 18608 2.70 18609 4.00 18610 3.00 18611 2.90 18612 3.90 18613 4.00 18614 4.60 18615 4.60 18616 3.75 18617 4.20 18618 4.55 18619 3.95 18620 3.80 18621 4.50 18622 2.90 18623 5.00 18624 5.00 Name: score, dtype: float64
在 Python 中所有常见数学运算符(如 +
,-
,*
,/
和 ^
)对于
DataFrame 或 Series 都起作用,并且对其中的每个元素也都适用。
Boolean Indexing in Pandas
如上所述,reviews
的 score
列中的所有值的平均值大约为
7。 我们如何找到所有得分超过这个平均分的游戏呢? 通长开始我们会做比较,将 Series 中的每个值与指定值进行比较,然后生成一个布尔类型的 Series,用来表示比较的状态。 例如,我们可以看到哪些行的 score
值大于
7:
score_filter = reviews["score"] > 7 score_filter
0 True 1 True 2 True 3 True 4 True 5 False 6 False 7 True 8 False 9 False 10 True 11 True 12 False 13 True 14 True 15 False 16 False 17 True 18 False 19 False 20 False 21 True 22 True 23 True 24 True 25 False 26 True 27 True 28 True 29 False ... 18595 False 18596 False 18597 False 18598 False 18599 False 18600 True 18601 True 18602 True 18603 True 18604 True 18605 False 18606 False 18607 False 18608 False 18609 True 18610 False 18611 False 18612 True 18613 True 18614 True 18615 True 18616 True 18617 True 18618 True 18619 True 18620 True 18621 True 18622 False 18623 True 18624 True Name: score, dtype: bool
一旦我们有一个 Boolean Series,我们可以使用它只选择 DataFrame 中的 Series 值 为 True 行。 因此,我们可以从 reviews
中只选择 score
大于
7 的行:
filtered_reviews = reviews[score_filter] filtered_reviews.head()
score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|
0 | Amazing | LittleBigPlanet PS Vita | /games/littlebigplanet-vita/vita-98907 | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
1 | Amazing | LittleBigPlanet PS Vita -- Marvel Super Hero E... | /games/littlebigplanet-ps-vita-marvel-super-he... | PlayStation Vita | 9.0 | Platformer | Y | 2012 | 9 | 12 |
2 | Great | Splice: Tree of Life | /games/splice/ipad-141070 | iPad | 8.5 | Puzzle | N | 2012 | 9 | 12 |
3 | Great | NHL 13 | /games/nhl-13/xbox-360-128182 | Xbox 360 | 8.5 | Sports | N | 2012 | 9 | 11 |
4 | Great | NHL 13 | /games/nhl-13/ps3-128181 | PlayStation 3 | 8.5 | Sports | N | 2012 | 9 | 11 |
可以使用多个条件进行过滤。 让我们找找在Xbox One
发布得分超过 7
的游戏。
在下面的代码中:
- 为过滤器设置两个条件:
- 检查
score
是否大于7
- 检查
platform
是否是Xbox One
- 给
reviews
应用上边的顾虑器来获取我们想要的行。
- 给
- 使用
head
方法打印filtered_review
的前 5 行。
xbox_one_filter = (reviews['score'] > 7) & (reviews['platform']=='Xbox one') filter_reviews = reviews[xbox_one_filter] filtered_reviews.head()
score_phrase | title | url | platform | score | genre | editors_choice | release_year | release_month | release_day | |
---|---|---|---|---|---|---|---|---|---|---|
17137 | Amazing | Gone Home | /games/gone-home/xbox-one-20014361 | Xbox One | 9.5 | Simulation | Y | 2013 | 8 | 15 |
17197 | Amazing | Rayman Legends | /games/rayman-legends/xbox-one-20008449 | Xbox One | 9.5 | Platformer | Y | 2013 | 8 | 26 |
17295 | Amazing | LEGO Marvel Super Heroes | /games/lego-marvel-super-heroes/xbox-one-20000826 | Xbox One | 9.0 | Action | Y | 2013 | 10 | 22 |
17313 | Great | Dead Rising 3 | /games/dead-rising-3/xbox-one-124306 | Xbox One | 8.3 | Action | N | 2013 | 11 | 18 |
17317 | Great | Killer Instinct | /games/killer-instinct-2013/xbox-one-20000538 | Xbox One | 8.4 | Fighting | N | 2013 | 11 | 18 |
当使用多个条件进行过滤时,将每个过滤条件放在括号中,并用 & 符号把它们连接起来。
Pandas Plotting
现在我们知道如何进行过滤,我们可以创建图来观察 Xbox One 的评论分布与 PS 4 的评论分布。 这将帮助我们了解哪个平台有更好的游戏。 我们可以通过直方图来做到这一点,这将绘制不同得分范围的游戏出现的次数,这将告诉我们哪个平台更多的高评级游戏。
我们可以使用 pandas.DataFrame.plot 方法,为每个平台创建一个直方图。这个方法利用流行的 Python 绘图库 matplotlib,从而生成好看的图标。
译者注: pip3 install matplotlib 安装 matplotlib 包
绘图方法默认为绘制线图。 我们需要传入关键字参数 kind =“hit”
来绘制一个直方图。
在下面的代码中,我们:
- 在 Jupyter notebook 中调用
%matplotlib inline
设置绘图。 - 从
reviews
中筛选只有 Xbox One 的数据。 - 绘制
score
列。
%matplotlib inline reviews[reviews["platform"] == "Xbox One"]["score"].plot(kind="hist")
<matplotlib.axes._subplots.AxesSubplot at 0x113988860>
我们同样可以绘制 PS 4 的直方图:
reviews[reviews["platform"] == "PlayStation 4"]["score"].plot(kind="hist")
<matplotlib.axes._subplots.AxesSubplot at 0x113a8d588>
从直方图看来,PS 4 具有比 Xbox One 更多的高评级游戏。
filtered_reviews["score"].hist()
<matplotlib.axes._subplots.AxesSubplot at 0x113cb6b70>
本站文章除注明转载外,均为本站原创或编译,如需转载,请联系微信公众号“编程派”获得授权。转载时,应注明来源、作者及原文链