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更加酷炫,而且圖還更好看。上面例子都是本人親測,一個個對比,原創文章,大家如果有其他問題可以留言討論。