本文介紹瞭如何在 Python 中利用散點圖矩陣(Pairs Plots)進行資料視覺化。
如何快速構建強大的探索性資料分析視覺化
當你得到一個很不錯的乾淨資料集時,下一步就是探索性資料分析(Exploratory Data Analysis,EDA)。EDA 可以幫助發現資料想告訴我們什麼,可用於尋找模式、關係或者異常來指導我們後續的分析。儘管在 EDA 中有很多種可以使用的方法,但是其中最有效的啟動工具之一就是散點圖矩陣(pairs plot,也叫做 scatterplot matrix)。散點圖矩陣允許同時看到多個單獨變數的分佈和它們兩兩之間的關係。散點圖矩陣是為後續分析識別趨勢的很棒方法,幸運的是,用 Python 實現也是相當簡單的。
本文,我們將介紹如何使用 Seaborn 視覺化庫(https://seaborn.pydata.org/)在 Python 中啟動和執行散點圖矩陣。我們將看到如何為快速檢查資料而建立預設散點圖矩陣,以及如何為了更深入的分析定製視覺化方案。
程式碼地址:https://github.com/WillKoehrsen/Data-Analysis/blob/master/pairplots/Pair%20Plots.ipynb
我們將探索一個現實世界資料集,它由國家級的社會經濟資料組成,這些資料都是 Gapminder 收集的。
Seaborn 中的散點圖矩陣
我們需要先了解一下資料,以便開始後續的進展。我們可以 pandas 資料幀的形式載入這些社會經濟資料,然後我們會看到下面這些列:
每一行代表一個國家一年的觀察資料,列代表變數(這種格式的資料被稱作整潔資料,tidy data),其中有兩個類別列(國家和洲)和四個數值列。這些列簡單易懂:life_exp 是出生時的預期壽命,以年為單位,popis 是人口數量,gdp_per_cap 是人均 GDP(以國際元)為單位。
seaborn 中的預設散點圖矩陣僅僅畫出數值列,儘管我們隨後也會使用類別變數來著色。建立預設的散點圖矩陣很簡單:我們載入 seaborn 庫,然後呼叫 pairplot 函式,向它傳遞我們的資料幀即可:
# Seaborn visualization library
import seaborn as sns
# Create the default pairplot
sns.pairplot(df)
我仍舊大為吃驚,一行簡單的程式碼就能夠讓我們得到整個圖。散點圖矩陣會構建兩種基本圖形:直方圖和散點圖。位於對角線位置的直方圖讓我們看到了每一個變數的分佈,而對角線上下的散點圖則展示了變數兩兩之間的關係。例如,第二行最左側的散點圖展示了 life_exp 和 year 之間的關係。
預設的散點圖矩陣通常能夠提供有價值的洞見。我們可以看到 life-exp 和 gdp_per_cap 是正相關的,這表明較高收入國家的國民要活得更久一些(儘管這並不能表明二者存在因果關係)。令人欣慰的是,這也顯示出世界範圍內的人口壽命隨著時間逐漸增長。我們可以從直方圖中瞭解到人口和 GDP 變數呈嚴重右偏態分佈。為了在以後的圖中更好地展示這些變數,我們可以透過對列數值取對數來進行列變換:
# Take the log of population and gdp_per_capita
df['log_pop'] = np.log10(df['pop'])
df['log_gdp_per_cap'] = np.log10(df['gdp_per_cap'])
# Drop the non-transformed columns
df = df.drop(columns = ['pop', 'gdp_per_cap'])
儘管這一張圖在分析中就很有用,然而我們發現基於類別變數(例如洲)對圖進行著色能夠讓它更有價值。這在 seaborn 中也是極其簡單的。我們唯一要做的就是在呼叫 sns.pairplot 函式的時候使用關鍵詞 hue。
sns.pairplot(df, hue = 'continent')
現在我們發現大洋洲和歐洲趨向於擁有最高的期望壽命,而亞洲擁有最多的人口量。注意我們對人口和 GDP 的對數變換使得這些變數呈正態分佈,這提供了一個關於這些變數更加全面的表徵。
這張圖具有更多的資訊,但是還存在一些問題:正如對角線上看到的一樣,我認為堆疊的直方圖可解釋性不是很好。展示來自多類別的單變數分佈的一個更好方法就是密度圖(density plot)。我們可以透過呼叫函式將直方圖變成密度圖。向散點圖輸入一些關鍵詞,改變點的透明度、大小和邊緣顏色。
# Create a pair plot colored by continent with a density plot of the # diagonal and format the scatter plots.
sns.pairplot(df, hue = 'continent', diag_kind = 'kde',
plot_kws = {'alpha': 0.6, 's': 80, 'edgecolor': 'k'},
size = 4)
對角線上的密度圖使得對比洲之間的分佈相對於堆疊的直方圖更加容易。改變散點圖的透明度增加了圖的可讀性,因為這些圖存在相當多的重疊(ovelapping)。
現在是預設散點圖矩陣的最後一個例子。為減少複雜度,我們僅畫出 2000 年以後的資料。我們仍舊把洲著色,但是不畫出「年」這一列。為了限制畫出的列的數量,我們給函式傳遞了一個 vars 列表。為了更好的闡明這個圖,我們還加上了標題。
# Plot colored by continent for years 2000-2007
sns.pairplot(df[df['year'] >= 2000],
vars = ['life_exp', 'log_pop', 'log_gdp_per_cap'],
hue = 'continent', diag_kind = 'kde',
plot_kws = {'alpha': 0.6, 's': 80, 'edgecolor': 'k'},
size = 4);
# Title
plt.suptitle('Pair Plot of Socioeconomic Data for 2000-2007',
size = 28);
現在開始變得相當好看了!如果繼續建模,我們可能會使用這些圖中的資訊指導我們的選擇。例如,我們知道 log_gdp_per_cap 與 life_exp 是成正相關的,所以我們會建立一個線性模型來量化這種關係。本文主要集中在畫圖上面,如果希望更多地探索資料,我們可以使用 PairGrid 類定製散點圖。
使用 PairGrid 的定製化
與 sns.pairplot 函式相反,sns.PairGrid 是一個類,這意味著它不能自動填充圖。我們建立一個類例項,然後為網格的不同部分匹配特定的函式。為了給資料建立 PairGrid 例項,我們使用了以下的程式碼,這也限制了我們所展示的變數:
# Create an instance of the PairGrid class.
grid = sns.PairGrid(data= df_log[df_log['year'] == 2007],
vars = ['life_exp', 'log_pop',
'log_gdp_per_cap'], size = 4)
如果我們要顯示內容的話,則會得到一個空圖,因為我們還沒有為網格部分匹配任何函式。一個 PairGrid 需要填充三個網格部分:上三角、下三角和對角線。為了給這些部分匹配圖,我們使用在這一部分使用 grid.map 方法。例如,為了給上三角匹配一個散點圖,我們使用:
# Map a scatter plot to the upper triangle
grid = grid.map_upper(plt.scatter, color = 'darkred')
map_upper 方法採用任意接受兩個變數陣列的函式(例如 plt.scatter),以及相關的關鍵詞(例如 color)。map_lower 方法幾乎與其相同,但是它填充的是網格的下三角。map_diag 與這兩者稍有不同,因為它採用接受單個陣列的函式(回想一下,對角線只顯示單個變數)。一個例子是 plt.hist,我們使用它來填充對角線部分:
# Map a histogram to the diagonal
grid = grid.map_diag(plt.hist, bins = 10, color = 'darkred',
edgecolor = 'k')
# Map a density plot to the lower triangle
grid = grid.map_lower(sns.kdeplot, cmap = 'Reds')
在這個例子中,我們在下三角中使用二維核密度估計(即密度圖)。將上面的內容合在一起,這段程式碼就會給出下圖:
當我們想要建立自定義函式將不同的資訊匹配到該圖時,使用 PairGrid 類的實際好處就會顯露出來。例如,我可能希望在散點圖上增加兩個變數的皮爾遜相關係數。為了做到這一點,我會寫一個使用兩個陣列的函式,用它來計算統計資料,然後畫在圖上。下面的程式碼展示的就是如何做到這件事(來源:https://stackoverflow.com/questions/30942577/seaborn-correlation-coefficient-on-pairgrid)。
# Function to calculate correlation coefficient between two arrays
def corr(x, y, **kwargs):
# Calculate the value
coef = np.corrcoef(x, y)[0][1]
# Make the label
label = r'$\rho$ = ' + str(round(coef, 2))
# Add the label to the plot
ax = plt.gca()
ax.annotate(label, xy = (0.2, 0.95), size = 20, xycoords = ax.transAxes)
# Create a pair grid instance
grid = sns.PairGrid(data= df[df['year'] == 2007],
vars = ['life_exp', 'log_pop', 'log_gdp_per_cap'], size = 4)
# Map the plots to the locations
grid = grid.map_upper(plt.scatter, color = 'darkred')
grid = grid.map_upper(corr)
grid = grid.map_lower(sns.kdeplot, cmap = 'Reds')
grid = grid.map_diag(plt.hist, bins = 10, edgecolor = 'k', color = 'darkred');
我們的新函式被匹配到上三角中了,因為我們需要兩個陣列來計算相關係數(還要注意到,我們可以將多個函式匹配到網格部分中)。這樣就得到了下圖:
現在相關係數已經出現在上面的散點圖上了。這是一個比較直接的例子,但是我們可以使用 PairGrid 對映任何一個我們想要對映到圖上的函式。我們可以按照需要增加相關的資訊,這可以幫助我們解決如何寫這個函式的問題!最後一個例子,下圖對角線上展示了總結統計資訊:
雖然還需要一些整理,但是它展示了一個通用的思想:除了使用庫中現有的函式將資料對映到圖上,例如 matplotlib,我們可以寫自己的函式來展示自定義資訊。
總結
散點圖矩陣(pairs plots)是一款強大的工具,可以快速探索資料集中的分佈和關係。為了讓散點圖矩陣可定製、可擴充套件,Seaborn 透過 Pair Grid 類提供了一個簡單的預設方法。在資料分析專案中,大部分的價值通常不是來自於酷炫的機器學習,而是來自對資料的直接視覺化。散點圖矩陣給我們提供了對資料的概覽,是資料分析專案很棒的起點。
原文連結:https://towardsdatascience.com/visualizing-data-with-pair-plots-in-python-f228cf529166