Seaborn中文教程(二):分類數(shù)據(jù)可視化

在統(tǒng)計關(guān)系可視化教程中,我們學(xué)會了使用多種不同的方式來展示一個數(shù)據(jù)集中多個變量之間的關(guān)系。在一系列的例子中,我們聚焦于那些關(guān)系主要存在于兩個數(shù)值型變量之間的情況。然而當(dāng)其中一個變量是分類(離散)變量時,我們不妨使用更加有針對性的可視化方法。

seaborn中,有多種不同的方式來展示包含了分類數(shù)據(jù)的變量關(guān)系。正如relplot()scatterplot()/lineplot()之間的關(guān)系一樣,我們可以使用catplot()函數(shù)來描述分類數(shù)據(jù),也可以使用更多坐標(biāo)軸級別的繪圖函數(shù)來完成這些任務(wù)。catplot()提供了對這些axes-level的函數(shù)的整合,將他們放在了一個更高級別的統(tǒng)一的接口之中。

我們將分類可視化圖形分為三類,并且之后我們會詳細(xì)探討他們:

  1. 分類散點(diǎn)圖
  • stripplot(): 或catplot(kind="strip")
  • swarmplot(): 或catplot(kind="swarm")
  1. 分類分布圖
  • boxplot(): 或catplot(kind="box")
  • violinplot(): 或catplot(kind="violin")
  • boxenplot(): 或catplot(kind="boxen")
  1. 分類統(tǒng)計估計圖
  • pointplot(): 或catplot(kind="point")
  • barplot(): 或catplot(kind="bar")
  • countplot(): 或catplot(kind="count")

這些分類從不同的粒度來展示數(shù)據(jù)。想要知道哪個更合適,就需要我們認(rèn)真思考我們到底要回答什么問題。catplot()提供的統(tǒng)一的API可以幫助我們輕松地在不同方法間切換并從不同的視角理解數(shù)據(jù)。

在這篇教程中,我們會主要使用圖形級別的整合接口:catplot()。我們已經(jīng)知道了這個函數(shù)是上邊那一系列繪圖方法的更高級別的整合接口,因此當(dāng)我們詳細(xì)討論到了某種圖形時,我們也會深涉及到這些稍底層的方法,這樣我們就不會錯過那些僅在某些方法中存在的API。

import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="ticks", color_codes=True)

一、分類散點(diǎn)圖

catplot()默認(rèn)的處理方式就是散點(diǎn)圖。在繪制分類散點(diǎn)圖時,我們會遇到一個挑戰(zhàn),當(dāng)在同一個類別中出現(xiàn)大量取值相同或接近的觀測數(shù)據(jù)時,他們會擠到一起。seaborn中有兩種分類散點(diǎn)圖,分別以不同的方式處理了這個問題。catplot()使用的默認(rèn)方式是stripplot(),它給這些散點(diǎn)增加了一些隨機(jī)的偏移量:

tips = sns.load_dataset("tips")
sns.catplot(x="day", y="total_bill", data=tips);
image

jitter參數(shù)控制著偏移量的大小,或者我們可以直接禁止他們偏移:

sns.catplot(x="day", y="total_bill", jitter=False, data=tips);
image

第二種解決方式使用算法避免了散點(diǎn)之間的重合。它提供了更好的方式來呈現(xiàn)觀測點(diǎn)的分布,但是它僅適用于較小的數(shù)據(jù)集。這種圖被叫做蜂群圖,在seaborn中我們用swarmplot()或者catplot(kind="swarm")來繪制它:

sns.catplot(x="day", y="total_bill", kind="swarm", data=tips);
image

與關(guān)系圖(relplot())類似,我們也可以使用hue參數(shù)來增加一個新的維度(但是分類圖不支持sizestyle)。不同的分類圖對于hue參數(shù)的處理不太一樣,對于散點(diǎn)圖而言,它僅僅控制散點(diǎn)的顏色就足夠了:

sns.catplot(x="day", y="total_bill", hue="sex", kind="swarm", data=tips);
image

與連續(xù)數(shù)值型數(shù)據(jù)不同,如何在坐標(biāo)軸上對分類變量進(jìn)行排序并不總是那么顯而易見。一般情況下,seaborn分類圖函數(shù)會嘗試推斷數(shù)據(jù)集中分類的順序。如果你的數(shù)據(jù)是pandasCategorical類型,那么默認(rèn)的分類順序可以在pandas中設(shè)置;如果數(shù)據(jù)看起來是數(shù)值型的(比如1,2,3...),那他們也會被排序。但是即使我們使用數(shù)字作為不同分類的標(biāo)簽,它們?nèi)匀皇潜划?dāng)做分類型數(shù)據(jù)按順序繪制在分類變量對應(yīng)的坐標(biāo)軸上的:

# 注意,2和4之間的距離與1和2之間的距離是一樣的,它們是不同的分類,只會排序,但是并不會改變它們在坐標(biāo)軸上的距離
sns.catplot(x="size", y="total_bill", kind="swarm", data=tips.query("size != 3"));
image

我們還可以通過order參數(shù)指定分類的順序,當(dāng)我們需要繪制多個分類變量圖時這一點(diǎn)會很重要:

sns.catplot(x="smoker", y="tip", order=["No", "Yes"], data=tips);
image

我們前邊涉及到過“分類坐標(biāo)軸”,在這些例子中,我們的分類水平都與水平坐標(biāo)軸綁定。但是有些時候我們把分類變量放在垂直坐標(biāo)軸上會更有幫助(尤其是當(dāng)分類名稱較長或者分類較多時)。我們只需要交換x和y分配的變量即可:

sns.catplot(x="total_bill", y="day", hue="time", kind="swarm", data=tips);
image

二、分類分布圖

當(dāng)數(shù)據(jù)集的大小越來越大,分類散點(diǎn)圖在表現(xiàn)不同分類的觀測值的分布信息時就越發(fā)顯得捉襟見肘。此時,我們有一些方法,能以清晰明了的對比方式來總結(jié)不同分類下的觀測值分布信息。

箱線圖

第一種就是我們的老朋友:箱線圖。它能在圖中展現(xiàn)出數(shù)據(jù)的上下四分位數(shù)、中文數(shù)以及一些極值。箱體上下方的須線會分別向上和向下延伸1.5倍IQR(上下四分位數(shù)之間的距離),落在這個區(qū)域之外的點(diǎn)會單獨(dú)顯示為離群點(diǎn)(異常值)。

sns.catplot(x="day", y="total_bill", kind="box", data=tips);
image

我們可以增加一個hue參數(shù),這樣就可以進(jìn)一步增加一個維度來觀察數(shù)據(jù)分布:

sns.catplot(x="day", y="total_bill", hue="smoker", kind="box", data=tips);
image

這種操作叫做“dodging”,它會默認(rèn)保持打開,因?yàn)樗僭O(shè)hue參數(shù)對應(yīng)的變量與坐標(biāo)軸上的分類變量是相互嵌套的。假如事實(shí)并非如此,我們可以關(guān)閉“dodging”:

tips["weekend"] = tips["day"].isin(["Sat", "Sun"])
sns.catplot(x="day", y="total_bill", hue="weekend", kind="box", dodge=False, data=tips);
image

boxenplot()是一個與boxplot()相關(guān)的函數(shù),它繪制的是與箱線圖相似但是能展示更多關(guān)于數(shù)據(jù)分布形狀的信息,它對大數(shù)據(jù)更加友好:

diamonds = sns.load_dataset("diamonds")
sns.catplot(x="color", y="price", kind="boxen", data=diamonds.sort_values("color"));
image

小提琴圖

另一種方法是violinplot(),它將箱線圖與核密度估計過程結(jié)合了起來:

sns.catplot(x="total_bill", y="day", hue="time", kind="violin", data=tips);
image

這種方法通過和密度估計提供了關(guān)于數(shù)據(jù)分布的更多信息。另外,箱線圖中的分位數(shù)和須線也都在小提琴圖中有所體現(xiàn)。但是由于小提琴圖引入了KDE(核密度估計),所以相對于簡單明了的箱線圖,我們可能需要調(diào)整更多的參數(shù)。

sns.catplot(x="total_bill", y="day", hue="time",
            kind="violin", bw=.15, cut=0, data=tips);
image

當(dāng)一個額外的分類變量僅有2個水平時,我們也可以將它賦給hue參數(shù),并且設(shè)置split=True,這樣我們可以更加充分地利用空間來表達(dá)更多信息:

sns.catplot(x="day", y="total_bill", hue="sex",
            kind="violin", split=True, data=tips);
image

在小提琴圖中,我們有許多選項可以調(diào)整小提琴內(nèi)部的內(nèi)容,比如我們可以展示每個觀測點(diǎn)的位置而非統(tǒng)計量:

sns.catplot(x="day", y="total_bill", hue="sex",
            kind="violin", inner="stick", split=True,
            palette="pastel", data=tips);
image

我們還可以將swarmplot()stripplot()與箱線圖或者小提琴圖結(jié)合起來,這樣我們就可以同時看到每個觀測值的分布以及關(guān)于分布形態(tài)的統(tǒng)計量情況(分位數(shù)、極值等):

g = sns.catplot(x="day", y="total_bill", kind="violin", inner=None, data=tips)
sns.swarmplot(x="day", y="total_bill", color="k", size=3, data=tips, ax=g.ax);
image

三、分類統(tǒng)計估計圖

在某些應(yīng)用場景中,相對于展示每個分類的數(shù)據(jù)分布,我們可能更想展示每個分類中數(shù)據(jù)的集中趨勢估計(統(tǒng)計量,比如均值、中位數(shù)、方差等)。seaborn有兩種方式來展示此類信息。需要知道的是,這些函數(shù)基本的API與前邊提到的那些繪圖函數(shù)是一致的。

條形圖

一種常見的圖形是條形圖。在seaborn中,barplot()函數(shù)在整個數(shù)據(jù)集上運(yùn)行,并且應(yīng)用一個函數(shù)來獲得那些統(tǒng)計量(默認(rèn)為均值)。當(dāng)每個分類中有多個觀測值時,它還可以通過自助采樣法計算出一個置信區(qū)間,并且通過誤差棒的方式繪制出來。

titanic = sns.load_dataset("titanic")
sns.catplot(x="sex", y="survived", hue="class", kind="bar", data=titanic);
image

一個特例是我們想要展示每個分類下觀測值(樣本)的數(shù)量而非統(tǒng)計量。這就像是“屬于分類變量而非連續(xù)變量的直方圖”。在seaborn中,我們可以使用countplot()輕易地達(dá)成目的:

sns.catplot(x="deck", kind="count", palette="ch:.25", data=titanic);
image

barplot()countplot()在調(diào)用的時候支持所有我們在上邊討論過的選項(參數(shù)),同時一些額外支持的參數(shù)在它們各自的詳細(xì)文檔中可以找到:

sns.catplot(y="deck", hue="class", kind="count",
            palette="pastel", edgecolor=".6",
            data=titanic);
image

點(diǎn)圖

我們也可以使用pointplot()來表現(xiàn)同樣的信息。點(diǎn)圖也使用高度來編碼統(tǒng)計量,但是區(qū)別在于它不會畫出一個完整的長條,而是用一個點(diǎn)以及置信區(qū)間來替代;另外,它還會將屬于同一個hue分類的點(diǎn)連起來。這樣,我們就可以很容易看到hue變量是如何影響坐標(biāo)軸上的分類變量的(交互作用),因?yàn)椴煌€條的斜率簡直是一目了然:

sns.catplot(x="sex", y="survived", hue="class", kind="point", data=titanic);
image

我們前邊提到,分類繪圖函數(shù)是沒有style這一參數(shù)的(在relplot()中有)。但是我們同樣可以修改線條和點(diǎn)的樣式,使得我們的圖片更有可讀性,甚至可以在黑白色調(diào)下表現(xiàn)分類信息(考慮到色盲讀者時,黑白色調(diào)會很有幫助):

sns.catplot(x="class", y="survived", hue="sex",
            palette={"male": "g", "female": "m"},
            markers=["^", "o"], linestyles=["-", "--"],
            kind="point", data=titanic);
image

四、繪制“寬表”數(shù)據(jù)

雖然我們推薦使用使用長數(shù)據(jù)或者整齊的數(shù)據(jù)(類似一維數(shù)組),但是寬表類的數(shù)據(jù)在seaborn中也是得到了支持的。寬表類數(shù)據(jù)是指二維的數(shù)據(jù),比如pandasDataFrame或者numpy的二維數(shù)組。這些對象可以直接傳遞給data參數(shù)。

iris = sns.load_dataset("iris")
sns.catplot(data=iris, orient="h", kind="box")
<seaborn.axisgrid.FacetGrid at 0x1a209cb860>
image

另外,那些坐標(biāo)軸級別的繪圖函數(shù)(而非圖形級別、整合后的API)可以接受類似向量的數(shù)據(jù)輸入(比如pandasSeriesnumpy的一維數(shù)組):

sns.violinplot(x=iris.species, y=iris.sepal_length);
image

想要控制上邊我們討論的圖形的大小和形狀,我們需要使用更底層的matplotlib設(shè)置項:

f, ax = plt.subplots(figsize=(7, 3))
sns.countplot(y="deck", data=titanic, color="c");
image

這就是當(dāng)我們想要讓一個分類圖在一個復(fù)雜圖片中與其他子圖和平共處時需要采用的方法。

五、使用子圖展示多重關(guān)系

relplot()一樣,calplot()也是基于FacetGrid構(gòu)建,這意味著我們可以輕易地通過更多子圖來表現(xiàn)高維的關(guān)系:

sns.catplot(x="day", y="total_bill", hue="smoker",
            col="time", aspect=.6,
            kind="swarm", data=tips);
image

當(dāng)我們想要定制更多細(xì)節(jié)時,我們就需要使用FacetGrid對象支持的方法了:

g = sns.catplot(x="fare", y="survived", row="class",
                kind="box", orient="h", height=1.5, aspect=4,
                data=titanic.query("fare > 0"))
g.set(xscale="log");
image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容