1. 程式人生 > >利用Pandas進行資料分析

利用Pandas進行資料分析

原文:https://www.dataquest.io/blog/pandas-python-tutorial/

 

作者:Vik Paruchuri

 

譯者:linkcheng

Python 是進行資料分析的絕佳語言,主要原因是以資料為中心的 Python 包的奇妙生態系統。Pandas 就是其中之一,它使得匯入和分析資料更容易。

Pandas 以 NumPy 和 matplotlib 包為底層驅動,為您提供更方便的介面用來完成大多數資料分析和視覺化工作。

在這篇教程中,我們將使用 Pandas 來分析 IGN(一個熱門的視訊遊戲評論網站)的視訊遊戲評論資料。

在我們分析視訊遊戲評論的過程,將學習 Pandas 關鍵的概念,例如索引等。

1

像 “巫師 3” 這樣的遊戲在 PS4 上會比在 Xbox One 上獲得更好的評價嗎? 這個資料集可以幫助我們找出答案。

使用 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.csv")

把資料讀入到 DataFrame 後,Pandas 提供兩個方法讓我們快速打印出資料。

這兩個函式是:

我們用 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
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。 這裡有一些常見的:

我們可以使用 corr 方法來檢視是否有任何列與 score 相關。 例如,通過這種方式我們可以得到,最近釋出的遊戲是否獲得了更高的評價(release_year),或者是否年底釋出的遊戲得分更好(release_month):

reviews.corr()
score release_yea