作者|小雨
知乎| https://zhuanlan.zhihu.com/pypcfx
簡介|中途轉(zhuǎn)行的數(shù)據(jù)挖掘工程師
直方圖是一種可以快速展示數(shù)據(jù)概率分布的工具,直觀易懂,深受數(shù)據(jù)愛好者的喜愛。平時可能會看到matplotlib、seaborn等最高級的打包庫包,類似于下面的圖。
這個博主會總結(jié)所有使用Python繪制直方圖的方法,大致可以分為三類(詳細劃分為五類,參考文末總結(jié)):
純Python實現(xiàn)直方圖,不使用任何第三方庫使用Numpy來創(chuàng)建直方圖總結(jié)數(shù)據(jù)使用matplotlib,pandas,seaborn繪制直方圖下面,我們將逐一介紹每種方法的來龍去脈。
直方圖在純Python中的實現(xiàn)
在準備用純Python繪制直方圖時,最簡單的想法是顯示每個值在報表中出現(xiàn)的次數(shù)。在這種情況下,使用字典來完成這個任務(wù)是非常合適的。讓我們看看下面的代碼是如何實現(xiàn)的。
>。>。>。a = ( 0,1,1,1,2,3,7,7,23)
>。>。>。defcount_elements(seq)->格言:
..." " "從“序列”中計數(shù)元素。"""
...hist = {}
...fori inseq:
...hist[i] = hist.get(i,0) + 1
...returnhist
>。>。>。counted = count_elements(a)
>。>。>。計算
{ 0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}
我們可以看到count_elements()返回一個字典,字典中出現(xiàn)的鍵都是目標列表中唯一的值,值是所有值出現(xiàn)的頻率。用hist[i] = hist.get(i,0)+1,累加每個值的次數(shù),每次加1。
實際上,這個功能可以通過Python標準庫,即集合來完成。計數(shù)器類,兼容Pyhont字典,覆蓋字典的。update()方法。
>。>。>。從集合導入計數(shù)器
>。>。>。計數(shù)=計數(shù)器(a)
>。>。>。詳細敘述
計數(shù)器({ 0: 1,1: 3,3: 1,2: 1,7: 2,23: 1})
我們可以看到這種方法的結(jié)果和之前自己實現(xiàn)的方法是一樣的,也可以通過集合來檢查兩種方法得到的結(jié)果是否相等。柜臺
>。>。>。counted.items() == counted.items()
真正的
我們用上面的函數(shù)重新創(chuàng)建了一個輪子ASCII _直方圖,最后通過Python的輸出格式format實現(xiàn)了直方圖的顯示。代碼如下:
defascii _直方圖(seq)->無:
" " "水平頻率表/直方圖。"""
counted = count_elements(seq)
叉入(計數(shù)):
打印(' {0:5d} {1} '。格式(k,'+'* counted[k])
該函數(shù)以數(shù)值的順序繪制,數(shù)值出現(xiàn)的次數(shù)用(+)表示。在字典中調(diào)用sorted()會按順序返回一個鍵列表,然后就可以得到對應(yīng)的counted[k]的個數(shù)。
>。>。>。隨機導入
>。>。>。random.seed( 1)
>。>。>。val =[1,3,4,6,8,9,10]
>。>。>。# `vals中的數(shù)字將出現(xiàn)5到15次
>。>。>。freq = (random.randint( 5,15)for _ in val)
>。>。>。數(shù)據(jù)= []
>。>。>。對于f,v in (freq,val):
...data.extend([v] * f)
>。>。>。ascii _直方圖(數(shù)據(jù))
1+++++++
3++++++++++++++
4++++++
6+++++++++
8++++++
9++++++++++++
10++++++++++++
在該代碼中,val中的值不重復,每個值的出現(xiàn)頻率由我們定義,并在5到15之間隨機選擇。然后,使用上面封裝的函數(shù),得到純Python版本的直方圖顯示。
總結(jié):純python實現(xiàn)頻率表(非標準直方圖),可以通過集合直接實現(xiàn)。計數(shù)器方法。
用Numpy實現(xiàn)直方圖
以上是一個使用純Python的簡單直方圖,但是從數(shù)學角度來說,直方圖是一個從盒子到頻率的映射,可以用來估計變量的概率密度函數(shù)。但是,上面的純Python實現(xiàn)版本只是一個簡單的頻率統(tǒng)計,并不是真正的直方圖。
因此,我們繼續(xù)從上面實現(xiàn)的簡單直方圖升級。一個真實的直方圖首先要把變量劃分成區(qū)域(框),也就是劃分成不同的區(qū)間,然后統(tǒng)計每個區(qū)間的觀測值個數(shù)。恰好Numpy的直方圖法可以做到這一點,不僅如此,也是后面要提到的matplotlib和熊貓使用的基礎(chǔ)。
比如看一組從拉普拉斯分布中提取的浮點樣本數(shù)據(jù)。該分布比標準正態(tài)分布具有更寬的尾部,并且具有兩個描述性參數(shù)(位置和規(guī)模):
>。>。>。將numpy導入為np
>。>。>。np.random.seed( 444)
>。>。>。np.set_printoptions(精度= 3)
>。>。>。d = np.random .拉普拉斯(loc= 15,scale= 3,size= 500)
>。>。>。d[ :5]
數(shù)組([ 18.406,18.087,16.004,16.221,7.358])
因為這是一個連續(xù)分布,不可能把每一個單個浮點值(也就是所有無數(shù)個小數(shù)位)都標注好(因為點太多)。但是你可以把數(shù)據(jù)分成盒子,然后統(tǒng)計每個盒子里觀測值的個數(shù),這才是真正的直方圖應(yīng)該做的。
我們來看看如何使用Numpy實現(xiàn)直方圖頻率統(tǒng)計。
>。>。>。hist,bin_edges = np .直方圖(d)
>。>。>。噓
數(shù)組([ 1,0,3,4,4,10,13,9,2,4])
>。>。>。bin_edges
數(shù)組([ 3.217,5.199,7.181,9.163,11.145,13.127,15.109,17.091,
19.073, 21.055, 23.037])
這個結(jié)果可能不是很直觀。比方說,np .直方圖()默認使用10個大小相同的區(qū)間(方框),然后返回一個元組(頻率,方框邊界),如上圖所示。需要注意的是,這個邊界的數(shù)量比盒子的數(shù)量多一個,可以簡單的用下面的代碼來確認。
>。>。>。hist.size,bin_edges.size
(10, 11)
這就是問題所在。Numpy如何劃分盒子?簡單的np .直方圖()就可以做到,但是我們還是不知道怎么實現(xiàn)。我們來解剖一下np .直方圖()的內(nèi)部,看看它是如何實現(xiàn)的(以上面提到的列表A為例)。
>。>。>。#取a的最小值和最大值。
>。>。>。first_edge,last_edge = a.min(),a.max()
>。>。>。N _ equal _ bins =默認設(shè)置10 # numpy,10盒
>。>。>。bin _ edges = NP . Lin space(start = first _ edge,stop=last_edge,
...num = n _ equal _ bins,端點=真)
...
>。>。>。bin_edges
數(shù)組([ 0。, 2.3, 4.6, 6.9, 9.2, 11.5, 13.8, 16.1, 18.4, 20.7, 23.])
解釋:首先獲取一個列表的最小值和最大值,然后設(shè)置默認的框數(shù),最后使用Numpy的linspace方法進行數(shù)據(jù)分段。分箱的結(jié)果也與實際情況吻合較好。0到23等分10份,23/10,所以每份的寬度是2.3。
除了np .直方圖,還有兩種方法可以實現(xiàn)同樣的功能:np.bincount()和np.searchsorted()。我們來看看代碼和對比結(jié)果。
>。>。>。bcounts = np.bincount(a)
>。>。>。hist,_= np .直方圖(a,range=( 0,a.max()),bin = a . max()+1)
>。>。>。np.array_equal(hist,bcounts)
真正的
>。>。>。#正在復制`集合.計數(shù)器'
>。>。>。dict((np.unique(a),bcounts[bcounts .非零()]))
{ 0: 1, 1: 3, 2: 1, 3: 1, 7: 2, 23: 1}
綜上所述,直方圖可以用Numpy來實現(xiàn),可以直接用np .直方圖()或者np.bincount()來實現(xiàn)。
用Matplotlib和熊貓可視化直方圖
從上面的研究中,我們看到了如何使用Python的基本工具構(gòu)建直方圖。讓我們看看如何使用更強大的Python庫包來完成直方圖。Matplotlib基于Numpy直方圖進行了多樣化封裝,提供了更加完善的可視化功能。
importmatplotlib.pyplot asplt
# matplotlib . axes . axes . hist()方法的接口
n,bin,patches = plt.hist(x=d,bins = ' auto ',color= '#0504aa ',
α= 0.7,rwidth= 0.85)
plt.grid(軸= 'y ',α= 0.75)
plt.xlabel('值')
“頻率”
《我自己的直方圖》
plt.text( 23,45,r'$mu=15,b=3$ ')
maxfreq = n.max()
#設(shè)置y軸的上限
PLT . ylim(ymax = NP . ceil(max freq/10)* 10 ifmax freq % 10 else maxfreq+10)
之前我們定義了X軸上的分格邊界和Y軸上對應(yīng)的頻率。不難發(fā)現(xiàn)我們都是手動定義盒子數(shù)量的。但是,在上面的高級方法中,我們可以通過設(shè)置bins = ' auto '來自動選擇兩個編寫的算法中的最佳算法,并最終計算出最合適的bin數(shù)。這里,該算法的目的是選擇適當?shù)拈g隔(框)寬度,并生成最能代表數(shù)據(jù)的直方圖。
如果使用Python的科學計算工具,可以使用熊貓的Series .直方圖()并通過matplotlib.pyplot.hist()繪制輸入Series的直方圖,如下代碼所示。
進口熊貓aspd
尺寸,比例= 1000,10
通勤= pd。系列(np.random.gamma(比例,大小=大小)** 1.5)
通勤。繪圖。歷史(網(wǎng)格=真,箱= 20,rwidth= 0.9,
color= '#607c8e ')
PLT . title(' 1000名通勤者的通勤時間')
plt.xlabel('計數(shù)')
plt.ylabel(“通勤時間”)
plt.grid(軸= 'y ',α= 0.75)
熊貓。DataFrame .直方圖()的使用方式與Series相同,但會生成DataFrame數(shù)據(jù)中每一列的直方圖。
綜上,我們可以用Seris.plot.hist(),DataFrame.plot.hist(),matplotlib可以用matplotlib.pyplot.hist()實現(xiàn)直方圖。
繪制核密度估計(KDE)
KDE(核密度估計)是指核密度估計。用于估計隨機變量的概率密度函數(shù),可以使數(shù)據(jù)更加平滑。
如果使用熊貓庫,可以使用plot.kde()創(chuàng)建內(nèi)核密度圖。plot.kde()同時適用于Series和DataFrame數(shù)據(jù)結(jié)構(gòu)。但首先我們老公做了兩個不同的數(shù)據(jù)樣本做對比(兩個完全分布的樣本):
>。>。>。#兩個精確分布的樣本
>。>。>。平均值= 10,20
>。>。>。stdevs = 4,2
>。>。>。dist = pd。數(shù)據(jù)幀(
...np.random.normal(loc=means,scale=stdevs,size=( 1000,2)),
...列=[ 'a ',' b'])
>。>。>。dist.agg([ 'min ',' max ',' mean ',' std'])。四舍五入(小數(shù)= 2)
有
最小值- 1.5712.46
最大25.3226.44
平均值10.1219.94
標準3.941.94
如上所述,我們生成了兩組正態(tài)分布樣本,并通過一些描述性統(tǒng)計參數(shù)對兩組數(shù)據(jù)進行了簡單的比較。現(xiàn)在,我們可以在同一個Matplotlib軸上繪制每個直方圖及其對應(yīng)的kde。使用熊貓的plot.kde()的好處是會自動顯示所有列的直方圖和kde,非常方便使用。具體代碼如下:
圖,ax = plt .支線劇情()
dist.plot.kde(ax=ax,圖例= False,title= '直方圖:A對B ')
密度=真,軸=軸
ax.set_ylabel('概率')
ax.grid(軸= 'y ')
ax.set_facecolor( '#d8dcd6 ')
綜上,我們可以用Seris.plot.kde(),DataFrame.plot.kde()通過熊貓實現(xiàn)kde圖。
使用西伯恩的完美替代品
更高級的可視化工具是Seaborn,這是一個基于matplotlib的強大工具。對于直方圖,Seaborn有distplot()方法,可以同時繪制單變量分布和kde的直方圖,使用非常方便。以下是實現(xiàn)代碼(以上面生成的D為例):
importseaborn assns
sns.set_style( 'darkgrid ')
sns.distplot(d)
默認情況下,distplot方法將繪制kde,并提供擬合參數(shù),可以根據(jù)數(shù)據(jù)的實際情況選擇特殊的分布。
sns.distplot(d,fit=stats .拉普拉斯,kde= False)
注意兩個數(shù)字的細微差別。第一種情況,你在估計一個未知的概率密度函數(shù)(PDF),第二種情況,你知道分布,想知道哪些參數(shù)更能描述數(shù)據(jù)。
總結(jié):要通過seaborn實現(xiàn)直方圖,可以使用seaborn.distplot(),而seaborn也有單獨的kde繪圖,seaborn.kde()。
熊貓里的其他工具
除了繪圖工具,熊貓還提供了方便。value_counts()方法,用于計算非空值的直方圖,并將其轉(zhuǎn)換為熊貓的系列結(jié)構(gòu)。示例如下:
>。>。>。將熊貓作為pd導入
>。>。>。data = NP . random . choice(NP . arange(10),size= 10000,
...p=np.linspace( 1,11,10) / 60)
>。>。>。s = pd。系列(數(shù)據(jù))
>。>。>。s.value_counts()
91831
81624
71423
61323
51089
4888
3770
2535
1347
0170
dtype:int64
>。>。>。s.value_counts(normalize=True)。head()
90.1831
80.1624
70.1423
60.1323
50.1089
dtype:float64
另外,熊貓. cut()也是強行寧濱數(shù)據(jù)的便捷方法。比如我們有一些人的年齡數(shù)據(jù),我們想把這些數(shù)據(jù)按年齡組分類。例子如下:
>。>。>。ages = pd。系列(
...[ 1, 1, 3, 5, 8, 10, 12, 15, 18, 18, 19, 20, 25, 30, 40, 51, 52])
>。>。>。bin =(0,10,13,18,21,np.inf) #邊界
>。>。>。標簽=(“兒童”、“青春期前”、“青少年”、“軍齡”、“成人”)
>。>。>。group = PD . cut(age,bins = bins,labels=labels)
>。>。>。groups.value _ counts()
兒童6
成人5
青少年3
軍事_年齡2
青春期前1
dtype:int64
>。>。>。pd.concat((年齡,組),axis= 1)。重命名(列={ 0:'年齡',1:'組' })
年齡層
01兒童
11個孩子
23兒童
35兒童
48兒童
510兒童
612混凝土
715teen
818teen
918teen
1019軍事年齡
1120軍事年齡
1225成人
1330成人
1440成人
1551模塊
1652模塊
除了使用方便之外,更好的是這些操作最后都是用Cython代碼來完成的,運行速度也很快。
總結(jié):其他實現(xiàn)直方圖的方法都可以。value_counts()和熊貓. cut()。
應(yīng)該用哪種方法?
到目前為止,我們已經(jīng)學習了許多實現(xiàn)直方圖的方法。但是他們的缺點是什么?如何選擇他們?當然,沒有一種方法可以解決所有問題,也需要根據(jù)實際情況考慮如何選擇。以下是在某些情況下使用的方法的建議,僅供參考。
你的情況
推薦使用
注意
列表、元組或集合的數(shù)據(jù)結(jié)構(gòu)中有明確的整數(shù)數(shù)據(jù),您不想引入任何第三方庫
標準庫Collection.counter()提供了一種快速直接的頻率實現(xiàn)方法
這只是一個頻率表,并沒有真正意義上的直方圖的方塊劃分
大數(shù)組數(shù)據(jù),而你只想計算包含方框的直方圖(沒有可視化,純數(shù)學計算)
Numpy的np .直方圖()和np.bincount()對于直方圖的純數(shù)學計算很有幫助
有關(guān)更多信息,請參見np.digitize()
數(shù)據(jù)存在于熊貓的系列和數(shù)據(jù)幀對象中
熊貓方法,如Series.plot.hist(),DataFrame.plot.hist(),Series.value_counts(),and cut(),Series.plot.kde()和DataFrame.plot.kde()
參考熊貓的可視化部分
從任何數(shù)據(jù)結(jié)構(gòu)創(chuàng)建高度定制和可調(diào)的直方圖
推薦使用基于np .直方圖()的Pyplot.hist()函數(shù),使用頻率高,容易理解。
Matplotlib可以自定義
高級包裝的設(shè)計和集成(非定制)
Seaborn的distplot()可以方便地將直方圖和KDE圖結(jié)合起來
高級包裝
參考:https://realpython.com/python-histograms/
1.《histogram 5種方法教你用Python玩轉(zhuǎn)histogram直方圖》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點,與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《histogram 5種方法教你用Python玩轉(zhuǎn)histogram直方圖》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進行證實,對其原創(chuàng)性、真實性、完整性、及時性不作任何保證。
3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/tiyu/1030261.html