Pandas 好好用系列|快速瞭解 Pivot Table 與應用

學.誌|Chris Kang
不止數據|Not Only Data
10 min readNov 11, 2019

在現今的商業世界,樞紐(Pivot)分析已經是不可或缺的分析能力。透過樞紐分析,能快速的從雜亂無章的數據中抓取 insight,甚至掌握意料之外的趨勢。

而 Excel 本身就有提供方便的樞紐分析;但透過 Pandas 的 pivot Table,能夠更快速、更深入地把數據統整一齊呈現,因此學會 Pandas 的 Pivot Table 絕對能幫你更快找出數據中的 insight,就讓我們馬上開始吧!

如何使用 Pivot Table?

在開始介紹操作步驟前,先附上 Pivot Table 的函式做為參考:

pandas.pivot_table(data, values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All', observed=False)

常用參數:

  • data : 讀取你要使用的 DataFrame
  • index : 必要參數。此處輸入不想要變動的數據,作為想要比較的欄位基礎,該數據會成為第一欄的索引(index),此處能以 list、array 等方式輸入多個 index,則結果會以巢狀的方式呈現。
  • values : 可選。可以對需要計算的數據做篩選,如果以 list、array 等方式輸入多個 value,則能夠分別獲得該欄位的不同數值。
  • columns : 可選。用以分割數據,去選出想比較的特定欄位。
  • aggfunc : function 參數。是 Pivot Table 裡最厲害的功能,能夠引入 max、min 等內建參數,甚至能自訂 function 使用。

選用參數:

  • fill_value : 用特定值取代 NULL 的欄位。
  • margins : 布林值,用來確認是否顯示該欄位的加總。
  • margins_name : 字串,用來顯示上面 margin 增加的列或欄的名稱。
  • dropna : 布林值, 用以丟棄缺失值。
  • observed : 布林值,當 grouper 為 Categoricals 使用。

附上 Pandas 的 官方文件連結 以供參考。

實際案例操作:

這裡的案例實作,我們採用 Seaborn 所提供鐵達尼號的數據進行分析。在分析之前,先進行簡單的假說設立,以更深入的找出 insight。其中最核心的問題是:我們想要瞭解什麼樣類型的乘客,存活率最大?

以下是設立的假說:

  1. 通常越有錢的人,存活率越高。
  2. 根據之前的報導,大部分的男性會優先讓女性下船,因此理論上女性的存活率會較高。
  3. 由於女性的存活率較高,因此存活下來的人會由女性佔大多數。

一、引入 pandas 和察看數據

在開始分析前,先把必要的套件和資料都抓下來(從 seaborn 的資料庫抓取數據集)。接下來則來瞭解資料的型態、欄位以及缺失值的狀況,可以看到 age 和 deck 的缺失值明顯較多,因此在採用該欄資料時,就要特別注意資料是否有的問題。

接下來就利用 head() 來察看資料的狀況,可以看到 deck 在前面五筆資料就有缺失值,因此該欄位在後續的分析就必須剔除掉。

import pandas as pd
import numpy as np
import seaborn as sns
df = sns.load_dataset # 讀取數據df.info()
df.head()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
survived 891 non-null int64
pclass 891 non-null int64
sex 891 non-null object
age 714 non-null float64
sibsp 891 non-null int64
parch 891 non-null int64
fare 891 non-null float64
embarked 889 non-null object
class 891 non-null category
who 891 non-null object
adult_male 891 non-null bool
deck 203 non-null category
embark_town 889 non-null object
alive 891 non-null object
alone 891 non-null bool
dtypes: bool(2), category(2), float64(2), int64(4), object(5)
memory usage: 80.6+ KB

who adult_male deck embark_town alive alone
0 man True NaN Southampton no False
1 woman False C Cherbourg yes False
2 woman False NaN Southampton yes True
3 woman False C Southampton yes False
4 man True NaN Southampton no True

二、設定 index 以察看不同船艙等級的平均值

再來就是進行驗證之前假說的步驟了!首先,我們以 pclass(船艙等級)、sex(性別)、survived(是否存活) 來檢視資料。因為在前面的假說,我們希望瞭解在不同的船艙,年齡是否有明確的差異,藉此來進行初步的推論。

# 設定 index 以固定欄位
titanic_age = titanic.pivot_table(index=['pclass', 'sex', 'survived'])
print(titanic_age)
OUTPUT:
adult_male age alone fare parch \
pclass sex survived
1 female 0 0.000000 25.666667 0.333333 110.604167 1.333333
1 0.000000 34.939024 0.362637 105.978159 0.428571
male 0 1.000000 44.581967 0.649351 62.894910 0.259740
1 0.933333 36.248000 0.555556 74.637320 0.311111
2 female 0 0.000000 36.000000 0.500000 18.250000 0.166667
1 0.000000 28.080882 0.414286 22.288989 0.642857
male 0 1.000000 33.369048 0.714286 19.488965 0.142857
1 0.470588 16.022000 0.411765 21.095100 0.647059
3 female 0 0.000000 23.818182 0.319444 19.773093 1.097222
1 0.000000 19.329787 0.513889 12.464526 0.500000
male 0 0.936667 27.255814 0.773333 12.204469 0.213333
1 0.808511 22.274211 0.680851 15.579696 0.297872

sibsp
pclass sex survived
1 female 0 0.666667
1 0.549451
male 0 0.272727
1 0.377778
2 female 0 0.500000
1 0.485714
male 0 0.307692
1 0.529412
3 female 0 1.291667
1 0.500000
male 0 0.523333
1 0.340426

在設定 index 時,可以單純設定一個欄位並以 index=’age’ 的方式呈現,也能設定複數個參數,並以 List 的方式呈現,結果就會以階層狀的方式呈現數據。

其中我們可以發現,有一些欄位並沒有被顯示出來。原因是因為某些無法被統計的描述欄位,會被當作遺棄值(redundent)而拋棄,因此不會顯示在結果。

二、設定 value 以察看特定數據

為了更清楚瞭解上述提到三項變數對 age 的影響,因此我們特別只選出 age 的數據來分析。

# 設定 values
titanic_pclass_age = titanic.pivot_table(index=['pclass', 'sex', 'survived'], values='age')
OUTPUT:
age
pclass sex survived
1 female 0 25.666667
1 34.939024
male 0 44.581967
1 36.248000
2 female 0 36.000000
1 28.080882
male 0 33.369048
1 16.022000
3 female 0 23.818182
1 19.329787
male 0 27.255814
1 22.274211

從分析出的圖表,可以看到有趣的結果:

在頭等艙(pclass = 1):存活的男性與女性年紀差異不大,但未能存活的年紀女性明顯比男性為低。

商務艙(pclass = 2) :多由年紀明顯較小的乘客存活,也許該層的家庭出遊人數較多?此處就能夠在繼續往下進行數據探索。

經濟艙(pclass = 3):經濟艙的平均年齡明顯較頭等艙與商務艙低,可能由於年紀會影響可支配所得,因此較多年紀較輕的乘客選擇搭乘經濟艙。

三、設定 column 察看在不同性別與年齡的乘客存活率

接下來觀察性別和生存率的關係,可以發現女生的生存率是男生的好幾倍,也許就像我們看到的電影,在危難關頭男性都會請女性先下船。

# 設定在不同的性別下,個別的存活率
titanic_sex_sur = titanic.pivot_table(index=['sex'], columns='survived')
OUTPUT:
survived
sex
female 0.742038
male 0.188908

四、設定 aggfunc 以統計存活人數

知道女性的存活率高之後,就希望能瞭解女性的存活人數是不是因此就佔存活人數的大多數,這時 aggfunc 可以搭配 aggfunc 派上用場了。

可以發現女性雖然生存率較高,但仍然佔存活人數的少數,原因是因為原先乘客的性別比男性就佔了 64.7%。

# 對於數值 survived 分別進行平均值和計數
titanic_age_sur = titanic.pivot_table(index=['sex'], values='survived', margins=True, aggfunc=['mean', 'count'])
OUTPUT:
mean count
survived survived
sex
female 0.742038 314
male 0.188908 577
All 0.383838 891

上面的範例演示,只是簡單說明 Pivot 一部份的功能,要更快瞭解 Pivot 的概念,最快的方式就是找一份數據(可以參考文中的 titanic 數據),自己實際操作一次,不停地去比對 index、columns 和 values 之間的差異,以及如何結合 aggfunc 達到自己想要的統計數據。實際操作一次後,我保證你很快就能把 Pivot Table 的功能用的行雲流水。

謝謝你/妳,願意把我的文章閱讀完

如果你喜歡筆者在 Medium 的文章,可以拍個手(Claps),
也歡迎你分享給你覺得有需要的朋友們。

--

--

學.誌|Chris Kang
不止數據|Not Only Data

嗨!我是 Chris,一位擁有技術背景的獵頭,熱愛解決生活與職涯上的挑戰。專注於產品管理/資料科學/前端開發 / 人生成長,在這條路上,歡迎你找我一起聊聊。歡迎來信合作和交流: chriskang0917@gmail.com