1. 程式人生 > 程式設計 >Python資料視覺化:箱線圖多種庫畫法

Python資料視覺化:箱線圖多種庫畫法

概念

箱線圖通過資料的四分位數來展示資料的分佈情況。例如:資料的中心位置,資料間的離散程度,是否有異常值等。

把資料從小到大進行排列並等分成四份,第一分位數(Q1),第二分位數(Q2)和第三分位數(Q3)分別為資料的第25%,50%和75%的數字。

四分位間距(Interquartilerange(IQR))=上分位數(upper quartile)-下分位數(lower quartile)

箱線圖分為兩部分,分別是箱(box)和須(whisker)。箱(box)用來表示從第一分位到第三分位的資料,須(whisker)用來表示資料的範圍。

箱線圖從上到下各橫線分別表示:資料上限(通常是Q3+1.5IQR),第三分位數(Q3),第二分位數(中位數),第一分位數(Q1),資料下限(通常是Q1-1.5IQR)。有時還有一些圓點,位於資料上下限之外,表示異常值(outliers)。

(注:如果資料上下限特別大,那麼whisker將顯示資料的最大值和最小值。)

案例

1. 使用pandas自帶的函式

使用pandas裡的dataframe資料結構存放待顯示的資料。如果希望顯示的各個資料列表中,資料長度不一致,可以先用Series函式轉換為Series資料,再儲存到dataframe中,對應index的value值若不存在則為NaN。

下面我們隨機生成4組資料,看看他們的箱線圖。

【程式碼】

import numpy as np 
import pandas as pd 
from matplotlib import pyplot as plt 
def list_generator(mean,dis,number): # 封裝一下這個函式,用來後面生成資料 
 return np.random.normal(mean,dis * dis,number) # normal分佈,輸入的引數是均值、標準差以及生成的數量 
# 我們生成四組資料用來做實驗,資料量分別為70-100 
y1 = list_generator(0.8531,0.0956,70) 
y2 = list_generator(0.8631,0.0656,80) 
y3 = list_generator(0.8731,0.1056,90) 
y4 = list_generator(0.8831,0.0756,100) 
# 如果資料大小不一,記得需要下面語句,把陣列變為series 
y1 = pd.Series(np.array(y1)) 
y2 = pd.Series(np.array(y2)) 
y3 = pd.Series(np.array(y3)) 
y4 = pd.Series(np.array(y4)) 
data = pd.DataFrame({"1": y1,"2": y2,"3": y3,"4": y4,}) 
data.boxplot() # 這裡,pandas自己有處理的過程,很方便哦。 
plt.ylabel("ylabel") 
plt.xlabel("xlabel") # 我們設定橫縱座標的標題。 
plt.show() 

【效果】

上面的箱線圖很簡單,給出資料後,幾行程式碼就能生成,不過這是簡單的箱線圖。下面再看看稍微複雜點的。

2. 使用matplotlib庫畫箱線圖

我們上面介紹了使用pandas畫箱線圖,幾句命令就可以了。但是稍微複雜點的可以使用matplotlib庫。matplotlib程式碼稍微複雜點,但是很靈活。細心點同學會發現pandas裡面的畫圖也是基於此庫的,下面給你看看pandas裡面的原始碼:

通過原始碼可以看到pandas內部也是通過呼叫matplotlib來畫圖的。那下面我們自己實現用matplotlib畫箱線圖。

我們簡單模擬一下,男女生從20歲,30歲的花費對比圖,使用箱線圖來視覺化一下。

【程式碼】

import numpy as np 
import matplotlib.pyplot as plt 
fig,ax = plt.subplots() # 子圖 
def list_generator(mean,number) # normal分佈,輸入的引數是均值、標準差以及生成的數量 
 
# 我們生成四組資料用來做實驗,資料量分別為70-100 
# 分別代表男生、女生在20歲和30歲的花費分佈 
girl20 = list_generator(1000,29.2,70) 
boy20 = list_generator(800,11.5,80) 
girl30 = list_generator(3000,25.1056,90) 
boy30 = list_generator(1000,19.0756,100) 
 
data=[girl20,boy20,girl30,boy30,] 
ax.boxplot(data) 
ax.set_xticklabels(["girl20","boy20","girl30","boy30",]) # 設定x軸刻度標籤 
plt.show() 

【效果】

從上面隨機模擬,看出來男生花費趕不上女生吧,尤其是30歲以後,女生摔男生一大截啊。(模擬資料,請勿當真)

仔細看上面的圖,感覺還是不太好,既然男女生對比,那是不是要分組,男女生放一塊,然後再根據年齡段比較,這樣比較才直觀。

那我們就稍微改動上面一點點程式碼,實現男女生箱線圖捱得近一點。

【程式碼】

import numpy as np 
import matplotlib.pyplot as plt 
fig,100) 
 
 
data=[girl20,] 
# 用positions引數設定各箱線圖的位置 
ax.boxplot(data,positions=[0,0.6,3,3.7,])# 就是後面加了位置 
ax.set_xticklabels(["girl20",]) # 設定x軸刻度標籤 
plt.show() 

【效果】

這樣看一下,是不是男女生根據年齡段分組了呢,稍微比上面好看些,也直觀一些。這樣既能看出年齡段的對比,又能看出男女生的對比。

同樣,如果想要箱線圖旋轉90°,那麼也是在在 boxplot命令里加上引數 vert=False即可。如果想要更多設定,可以基於 boxplot函式引數進行修改,其函式定義如下:

boxplot(self,x,notch=None,sym=None,vert=None,whis=None,positions=None,widths=None,patch_artist=None,bootstrap=None,usermedians=None,conf_intervals=None,meanline=None,showmeans=None,showcaps=None,showbox=None,showfliers=None,boxprops=None,labels=None,flierprops=None,medianprops=None,meanprops=None,capprops=None,whiskerprops=None,manage_xticks=True,autorange=False,zorder=None)

3. 使用seaborn庫和matplotlib來畫箱線圖

Seaborn是基於matplotlib的Python視覺化庫。 它提供了一個高階介面來繪製有吸引力的統計圖形。Seaborn其實是在matplotlib的基礎上進行了更高階的API封裝,從而使得作圖更加容易,不需要經過大量的調整就能使你的圖變得精緻。但應強調的是,應該把Seaborn視為matplotlib的補充,而不是替代物。

函式定義:

boxplot(x=None,y=None,hue=None,data=None,order=None,hue_order=None,orient=None,color=None,palette=None,saturation=.75,width=.8,dodge=True,fliersize=5,linewidth=None,whis=1.5,notch=False,ax=None,**kwargs) 

【引數講解】 x,y:dataframe中的列名(str)或者向量資料

  • data:dataframe或者陣列
  • palette:調色盤,控制影象的色調
  • hue(str):dataframe的列名,按照列名中的值分類形成分類的條形圖
  • order,hue_order (lists of strings):用於控制條形圖的順序
  • orient:"v"|"h" 用於控制影象使水平還是豎直顯示(這通常是從輸入變數的dtype推斷出來的,此引數一般當不傳入x、y,只傳入data的時候使用)
  • fliersize:float,用於指示離群值觀察的標記大小
  • whis:確定離群值的上下界(IQR超過低和高四分位數的比例),此範圍之外的點將被識別為異常值。IQR指的是上下四分位的差值。
  • width:float,控制箱型圖的寬度

我們還是基於上面男女花費案例來說,不過這裡我們把資料進行了整理,做成了資料框dataframe。

【包含的庫】

import pandas as pd 
import numpy as np 
import seaborn as sns 
import matplotlib.pyplot as plt 
# plt.rc("font",family="SimHei",size="15") 避免中文亂碼,可不用

【程式碼第一部分】資料生成

def list_generator(mean,number) # normal分佈,輸入的引數是均值、標準差以及生成的數量 
 
# 我們生成四組資料用來做實驗,資料量分別為70-100 
# 分別代表男生、女生在20歲和30歲的花費分佈 
# 構造資料庫DataFrame 
num = 100 # 每組100個樣本 
girl20 = list_generator(1000,num) 
boy20 = list_generator(800,num) 
girl30 = list_generator(3000,num) 
boy30 = list_generator(1000,num) 
girl_sex = ['female' for _ in range(num)] 
boy_sex = ['male' for _ in range(num)] 
age20 = [20 for _ in range(num)] 
age30 = [30 for _ in range(num)] 
 
girl_d1 = pd.DataFrame({'cost': girl20,'sex': girl_sex,'age': age20}) 
boy_d1 = pd.DataFrame({'cost': boy20,'sex': boy_sex,'age': age20}) 
girl_d2 = pd.DataFrame({'cost': girl30,'age': age30}) 
boy_d2 = pd.DataFrame({'cost': boy30,'age': age30}) 
data = pd.concat([girl_d1,boy_d1,girl_d2,boy_d2]) 
 
print(data.head()) 

資料長啥樣?下面是給出的資料框前面的部分,一共400個樣本,分性別和年齡。

【程式碼第二部分】使用seaborn庫畫圖

簡單看看所有資料的分佈情況:

sns.boxplot(x="age",y="cost",data=data,hue="sex",width=0.5,linewidth=1.0,palette="Set3") 

根據性別分組:

sns.boxplot(x="age",palette="Set3") 

根據年齡分組:

sns.boxplot(x="sex",hue="age",palette="Set3") 

上面這些是seaborn庫的簡單使用,可以通過年齡看男女花費比較,也可以根據性別看不同年齡段的花費比較,還是比較直觀的。當然除此之外還有很多其他的炫技,大家可以自己嘗試。

總結

從上面來看,雖然我們是採用不同方法來畫箱線圖,但是最基本的都是呼叫matplotlib庫,這裡面pandas是最簡單的箱線圖視覺化,但是不靈活。而matplotlib雖然靈活,但是需要慢慢調,而且複雜。相比之下seaborn更加酷炫,而且圖還更好看。上面例子都是本人親測,一個個對比,原創文章,大家如果有其他問題可以留言討論。