在前一篇 Seaborn 測試中已了解 Seaborn 並非用來完全取代 Matplotlib, 而是擴充其統計繪圖功能, 使用時還是要匯入 Matplotlib, 顯示圖形仍然是使用 plt.show(). Seaborn 的好處是它提供預設主題背景來使圖形更美觀, 介面更簡單. 本系列之前的文章參考 :
Seaborn 教學文件參考 :
# https://www.python-graph-gallery.com/ (Seaborn 繪圖範例網站)
參考書目 :
- Python 網路爬蟲與資料視覺化 (旗標, 2017, 陳允傑) 第 14 章
- Python 資料可視化之美 (深智, 2020, 張傑) 第 3 章
- Python 資料科學手冊 (碁峰, 2017, 何敏煌譯) 第 4 章
- Python資料可視化攻略 (碁峰, 2021)
- Pandas 資料清理, 重塑, 過濾, 視覺化 (旗標, 2021) 第 12 章
在資料來源方面, Seaborn 有別於 Matplotlib 之處是支援 Pandas 的 DataFrame 資料結構, 且內建 load_dataset() 可載入線上資料集供學習者測試, 故以下測試均以此資料集為資料來源.
>>> import seaborn as sns
>>> sns.get_dataset_names()
['anagrams', 'anscombe', 'attention', 'brain_networks', 'car_crashes', 'diamonds', 'dots', 'exercise', 'flights', 'fmri', 'gammas', 'geyser', 'iris', 'mpg', 'penguins', 'planets', 'taxis', 'tips', 'titanic']
六. 關聯性圖表 (Relational plots) :
Seaborn 的關聯性圖表有下列三種 :
- 折線圖 lineplot()
- 散布圖 scatterplot() :
- 散點圖 relplot() :
折線圖適合用來呈現一個變數對連續時間變數的變化趨勢; 散布圖與散點圖則適合用來觀察兩個變數. 其中散點圖 relplot() 為與 Pandas 緊密結合之畫布等級 (figure-level) 函式, 可用 DataFrame 直接繪製出 Matplotlib 的多軸 (多子圖) 圖形, 一次畫出多種圖形. 折線圖函式 lineplot() 與散布圖函式 scatterplot 則是軸等級函式.
1. 折線圖 :
折線圖適合繪製時間序列變數, 可用來呈現資料的時間趨勢. 繪製折線圖可用軸等級的 lineplot() 函式或畫布等級的 relplot(kind='line') 函式.
首先用 sns.lineplot() 繪製折線圖, 其主要參數如下 :
lineplot(x, y, data [, hue, style, palette, markers, size, sizes, dashes])
說明如下 :
- x : X 軸資料欄位名稱 (字串)
- y : Y 軸資料欄位名稱 (字串)
- hue : 用來表示第三軸的色調 (字串)
- data : Pandas 的 DataFrame 資料
- style : 區分樣式的欄位名稱
- palette : 色彩範本
- markers : 是否顯示資料點標記 (True/False), 預設 False
- size : 線條寬度類型
- sizes : 線條寬度
- dashes : 是否使用虛線 (True/False), 預設 True
其中最重要的是 x, y, data 這三個參數, data 就是 DataFrame 變數名稱, x 與 y 是 DataFrame 中的欄位名稱字串, 分別指定 X, Y 軸的資料來源.
參考 :
以航班旅客數量資料集 'flight' 為例, 裡面有自 1949 年以來每個月的旅客數統計, 例如 :
>>> import seaborn as sns
>>> import matplotlib.pyplot as plt
>>> import pandas as pd
>>> df=sns.load_dataset('flights')
>>> df
year month passengers
0 1949 Jan 112
1 1949 Feb 118
2 1949 Mar 132
3 1949 Apr 129
4 1949 May 121
.. ... ... ...
139 1960 Aug 606
140 1960 Sep 508
141 1960 Oct 461
142 1960 Nov 390
143 1960 Dec 432
[144 rows x 3 columns]
可見這是一個典型的時間序列資料, 有 year, month, 以及 passenger 三個欄位, 資料是逐年再逐月排列, 如果直接繪製 passenger 對 year 的圖形, 會繪製出以平均值為中心, 與其 95% 信賴區間為範圍的折線圖, 例如 :
>>> sns.set()
>>> sns.lineplot(x="year", y="passengers", data=df)
<matplotlib.axes._subplots.AxesSubplot object at 0x000001CC3A2827F0>
>>> plt.show()
結果如下 :
可見除了折線外, 周圍還有陰影, 這是因為一個時間點 (例如 1949 年) 有多筆資料, Seaborn 會計算其平均值與 95% 的信賴區間, 平均值用來繪製圖中的折線, 而信賴區間則用來繪製折線周圍的陰影. 完整程式碼如下 :
測試 6-1 : 呼叫 lineplot() 繪製折線圖 (1) - 單變數多值 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
df=sns.load_dataset('flights')
sns.set()
sns.lineplot(x="year", y="passengers", data=df)
plt.show()
如果每個時間點只有一筆資料, 則就只有一條折線而沒有信賴區間的陰影區, 例如可呼叫 DataFrame 物件的 query() 函式搜尋五月份的旅客資料 :
>>> may_flights=df.query("month=='May'") # 搜尋 5 月份資料
>>> may_flights
year month passengers
4 1949 May 121
16 1950 May 125
28 1951 May 172
40 1952 May 183
52 1953 May 229
64 1954 May 234
76 1955 May 270
88 1956 May 318
100 1957 May 355
112 1958 May 363
124 1959 May 420
136 1960 May 472
可見 query() 會傳回一個新的 DataFrame 物件, 只包含每年五月份的旅客數, 以此 DatFrame 作為 資料源傳給 data 參數來繪製折線圖 :
>>> sns.lineplot(x="year", y="passengers", data=may_flights)
<matplotlib.axes._subplots.AxesSubplot object at 0x000001CC38FC9C50>
>>> plt.show()
結果如下 :
這樣就不會有信賴區間, 只有折線而已了. 完整程式碼如下 :
測試 6-2 : 呼叫 lineplot() 繪製折線圖 (2) - 單變數單值 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
df=sns.load_dataset('flights')
may_flights=df.query("month=='May'")
sns.set()
sns.lineplot(x="year", y="passengers", data=may_flights)
plt.show()
可以呼叫 DataFrame 物件的 pivot() 函式做樞紐分析, 這樣每年的資料會分月展開成不同欄位, 亦即原本的 passengers 欄位會被拆成 Jan~Dec 之 12 個月份, 例如 :
>>> flights_wide=df.pivot("year", "month", "passengers")
>>> flights_wide
month Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
year
1949 112 118 132 129 121 135 148 148 136 119 104 118
1950 115 126 141 135 125 149 170 170 158 133 114 140
1951 145 150 178 163 172 178 199 199 184 162 146 166
1952 171 180 193 181 183 218 230 242 209 191 172 194
1953 196 196 236 235 229 243 264 272 237 211 180 201
1954 204 188 235 227 234 264 302 293 259 229 203 229
1955 242 233 267 269 270 315 364 347 312 274 237 278
1956 284 277 317 313 318 374 413 405 355 306 271 306
1957 315 301 356 348 355 422 465 467 404 347 305 336
1958 340 318 362 348 363 435 491 505 404 359 310 337
1959 360 342 406 396 420 472 548 559 463 407 362 405
1960 417 391 419 461 472 535 622 606 508 461 390 432
可見 panssenger 欄位已經根據 month 欄位展開了, 以此做為資料源繪圖 :
>>> sns.lineplot(data=flights_wide)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000239302116A0>
>>> plt.ylabel('passengers')
Text(0, 0.5, 'passengers')
>>> plt.show()
此處因為呼叫 lineplot() 時無法指定 Y 軸欄位 (因 'passenger' 欄位已被展開), 畫出的圖形沒有 Y 軸標籤, 因此利用 Matplotlib 的 ylabel() 函式來設定, 結果如下 :
可見 Seaborn 會自動將各月欄位列為圖例 (legend), 圖形呈現每年各月旅客數之折線圖. 完整程式碼如下 :
測試 6-3 : 呼叫 lineplot() 繪製折線圖 (3) - 繪製多變數折線圖 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
sns.set()
df=sns.load_dataset('flights')
flights_wide=df.pivot("year", "month", "passengers")
sns.lineplot(data=flights_wide)
plt.ylabel('passengers')
plt.show()
從上面圖形可知, Seaborn 對於多變數的折線圖預設會用虛線來繪製, 這可以傳入 dashes=False 參數來改成實線, 例如 :
測試 6-4 : 呼叫 lineplot() 繪製折線圖 (4) - 顯示實線 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
sns.set()
df=sns.load_dataset('flights')
flights_wide=df.pivot("year", "month", "passengers")
sns.lineplot(data=flights_wide, dashes=False)
plt.ylabel('passengers')
plt.show()
結果如下 :
也可以傳入 markers=True 來顯示資料點標記, 例如 :
測試 6-5 : 呼叫 lineplot() 繪製折線圖 (5) - 顯示資料點標記 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
sns.set()
df=sns.load_dataset('flights')
flights_wide=df.pivot("year", "month", "passengers")
sns.lineplot(data=flights_wide, dashes=False, markers=True)
plt.ylabel('passengers')
plt.show()
結果如下 :
可見每一個資料點 (轉折處) 都自動標示不同的標記了 (依月份, 如圖例所示) .
在上面的範例中使用 DataFrame 物件的 pivot() 方法做樞紐分析將月份展開, 但 Seaborn 繪圖函式的 hue 參數可以直接將月份 month 當作第三維變數, 不需要樞紐分析展開 month 就可以直接畫出多變數的折線圖, 例如 :
測試 6-6 : 呼叫 lineplot() 繪製折線圖 (6) - 使用 hue 參數 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
sns.set()
df=sns.load_dataset('flights')
sns.lineplot(x='year', y='passengers', hue='month', data=df)
plt.show()
此處除了指定 x, y 欄位外, 還用 hue 參數指定第三維變數 month, 結果如下 :
另外還可以用 style 參數指定要以哪個欄位區分不同樣式, 例如 :
測試 6-7 : 呼叫 lineplot() 繪製折線圖 (7) - 使用 style 參數 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
sns.set()
df=sns.load_dataset('flights')
sns.lineplot(x='year', y='passengers', hue='month', style='month', data=df)
plt.show()
此例以 month 欄位區分樣式, 結果如下 :
結果與上面的測試 6-3 相同.
除了用 lineplot() 外, 呼叫 relplot() 並傳入 kind='line' 參數也可以繪製折線圖, 例如 :
測試 6-8 : 呼叫 relplot() 繪製折線圖 - 使用 kind='line' 參數 [看原始碼]
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
sns.set()
df=sns.load_dataset('flights')
sns.relplot(x='year', y='passengers', hue='month', kind='line', data=df)
plt.show()
結果如下 :
與上面用 lineplot() 所繪製的折線圖不同之處是, 圖例 (legend) 是放在圖形外的右側, 優點是不會跟圖形搶地盤. 當然也可以傳入 style 參數將實線改為虛線, 或傳入 markers 參數加上資料點標記.
沒有留言 :
張貼留言