簡體   English   中英

使用scipy擬合給定直方圖的分布

[英]Fitting a distribution given the histogram using scipy

我想使用scipy(在我的情況下,使用weibull_min)適合數據分布。 在直方圖而不是數據點的情況下,是否可以這樣做? 就我而言,由於直方圖具有大小為1的整數箱,所以我知道可以按以下方式推斷數據:

import numpy as np
orig_hist = np.array([10, 5, 3, 2, 1])

ext_data = reduce(lambda x,y: x+y, [[i]*x for i, x in enumerate(orig_hist)])

在這種情況下,ext_data將保存以下內容:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]

並使用以下方法構建直方圖:

np.histogram(ext_data, bins=5)

相當於orig_hist

但是,鑒於已經建立了直方圖,我想避免外推數據並使用orig_hist擬合分布,但是我不知道是否可以在擬合過程中直接使用它。 另外,是否有一個numpy函數可用於執行與我所示的推斷類似的操作?

我可能會誤解某些內容,但是我相信擬合直方圖正是您應該做的事情:您正在嘗試估算概率密度。 直方圖盡可能接近潛在的概率密度。 您只需要對其進行歸一化即可獲得1的整數,或者允許您的擬合模型包含任意前置因子。

import numpy as np
import scipy.stats as stats
import scipy.optimize as opt
import matplotlib.pyplot as plt

orig_hist = np.array([10, 5, 3, 2, 1])
norm_hist = orig_hist/float(sum(orig_hist))

popt,pcov = opt.curve_fit(lambda x,c: stats.weibull_min.pdf(x,c), np.arange(len(norm_hist)),norm_hist)

plt.figure()
plt.plot(norm_hist,'o-',label='norm_hist')
plt.plot(stats.weibull_min.pdf(np.arange(len(norm_hist)),popt),'s-',label='Weibull_min fit')
plt.legend()

當然,對於您給定的輸入,Weibull擬合將遠遠不能令人滿意:

適合數據

更新

正如我上面提到的,Weibull_min不適合您的樣本輸入。 更大的問題是它也不適合您的實際數據:

orig_hist = np.array([ 23., 14., 13., 12., 12., 12., 11., 11., 11., 11., 10., 10., 10., 9., 9., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6.], dtype=np.float32)

新的直方圖數據

該直方圖存在兩個主要問題。 正如我所說,第一個是不太可能與Weibull_min分布相對應:它最大接近零且尾巴很長,因此需要一個非平凡的Weibull參數組合。 此外,直方圖顯然僅包含分布的一部分。 這意味着我的上述規范化建議肯定會失敗。 您不可避免地要使用適合自己的任意比例尺參數。

根據Wikipedia上的公式手動定義了縮放的Weibull擬合函數:

my_weibull = lambda x,l,c,A: A*float(c)/l*(x/float(l))**(c-1)*np.exp(-(x/float(l))**c)

在此函數中, x是自變量, llambda (比例參數), ck (形狀參數), A是比例系數。 引入A的隱含優勢是您不必標准化直方圖。

現在,當我將此函數放到scipy.optimize.curve_fit ,我發現了您所做的事情:它實際上並不執行擬合,而是堅持使用初始的擬合參數,無論您設置了什么(使用p0參數;默認猜測是每個參數都設為1)。 curve_fit似乎認為擬合收斂了。

經過一個多小時的與牆壁相關的頭部撞擊,我意識到問題在於x=0處的奇異行為引發了非線性最小二乘算法。 通過排除您的第一個數據點,您可以對數據進行實際擬合。 我懷疑如果我們設置c=1並不允許它適合,那么這個問題可能會消失,但是允許它適合可能更有意義(所以我沒有檢查)。

這是相應的代碼:

import numpy as np
import scipy.optimize as opt
import matplotlib.pyplot as plt

orig_hist = np.array([ 23., 14., 13., 12., 12., 12., 11., 11., 11., 11., 10., 10., 10., 9., 9., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 8., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 7., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6., 6.], dtype=np.float32)

my_weibull = lambda x,l,c,A: A*float(c)/l*(x/float(l))**(c-1)*np.exp(-(x/float(l))**c)

popt,pcov = opt.curve_fit(my_weibull,np.arange(len(orig_hist))[1:],orig_hist[1:]) #throw away x=0!

plt.figure()
plt.plot(np.arange(len(orig_hist)),orig_hist,'o-',label='orig_hist')
plt.plot(np.arange(len(orig_hist)),my_weibull(np.arange(len(orig_hist)),*popt),'s-',label='Scaled Weibull fit')
plt.legend()

結果:

新適應

In [631]: popt
Out[631]: array([  1.10511850e+02,   8.82327822e-01,   1.05206207e+03])

最終擬合參數的順序為(l,c,A) ,形狀參數約為0.88 這對應於發散的概率密度,這解釋了為什么會彈出一些錯誤的原因:

RuntimeWarning:電源中遇到無效值

以及為什么從x=0的擬合中沒有數據點。 但是從數據和擬合之間的視覺一致性來看,您可以評估結果是否可接受。

如果您想過度使用它,可以嘗試使用np.random.weibull和這些參數生成點,然后將生成的直方圖與您自己的比較。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM