簡體   English   中英

使用 Scipy 擬合 Weibull 分布

[英]Fitting a Weibull distribution using Scipy

我正在嘗試重新創建最大似然分布擬合,我已經可以在 Matlab 和 R 中做到這一點,但現在我想使用 scipy。 特別是,我想估計我的數據集的 Weibull 分布參數。

我試過這個:

import scipy.stats as s
import numpy as np
import matplotlib.pyplot as plt

def weib(x,n,a):
    return (a / n) * (x / n)**(a - 1) * np.exp(-(x / n)**a)

data = np.loadtxt("stack_data.csv")

(loc, scale) = s.exponweib.fit_loc_scale(data, 1, 1)
print loc, scale

x = np.linspace(data.min(), data.max(), 1000)
plt.plot(x, weib(x, loc, scale))
plt.hist(data, data.max(), density=True)
plt.show()

得到這個:

(2.5827280639441961, 3.4955032285727947)

一個看起來像這樣的分布:

使用 Scipy 的 Weibull 分布

閱讀此http://www.johndcook.com/distributions_scipy.html 后,我一直在使用 exponweib exponweib 我還嘗試了 scipy 中的其他 Weibull 函數(以防萬一)。

In Matlab (using the Distribution Fitting Tool - see screenshot) and in R (using both the MASS library function fitdistr and the GAMLSS package) I get a (loc) and b (scale) parameters more like 1.58463497 5.93030013. 我相信這三種方法都使用最大似然法進行分布擬合。

使用 Matlab 的 Weibull 分布

如果您想要 go,我已經在此處發布了我的數據。 為了完整起見,我使用的是 Python 2.7,5。 Scipy 0.12,0。 R 2.15.2 和 Matlab 2012b。

為什么我得到不同的結果?

我的猜測是您想在保持位置固定的同時估計形狀參數和威布爾分布的尺度。 修復loc假設您的數據和分布的值是正值,下限為零。

floc=0保持位置固定為零, f0=1保持指數威布爾的第一個形狀參數固定為 1。

>>> stats.exponweib.fit(data, floc=0, f0=1)
[1, 1.8553346917584836, 0, 6.8820748596850905]
>>> stats.weibull_min.fit(data, floc=0)
[1.8553346917584836, 0, 6.8820748596850549]

與直方圖相比的擬合看起來不錯,但不是很好。 參數估計值比您提到的來自 R 和 matlab 的估計值要高一些。

更新

我能得到的最接近現在可用的圖是無限制擬合,但使用起始值。 情節仍然沒有達到頂峰。 注意前面沒有 f 的適合值用作起始值。

>>> from scipy import stats
>>> import matplotlib.pyplot as plt
>>> plt.plot(data, stats.exponweib.pdf(data, *stats.exponweib.fit(data, 1, 1, scale=02, loc=0)))
>>> _ = plt.hist(data, bins=np.linspace(0, 16, 33), normed=True, alpha=0.5);
>>> plt.show()

指數擬合

很容易驗證哪個結果是真正的 MLE,只需要一個簡單的函數來計算對數似然:

>>> def wb2LL(p, x): #log-likelihood
    return sum(log(stats.weibull_min.pdf(x, p[1], 0., p[0])))
>>> adata=loadtxt('/home/user/stack_data.csv')
>>> wb2LL(array([6.8820748596850905, 1.8553346917584836]), adata)
-8290.1227946678173
>>> wb2LL(array([5.93030013, 1.57463497]), adata)
-8410.3327470347667

exponweib和 R fitdistr (@Warren) 的fit方法的結果更好,並且具有更高的對數似然。 它更有可能是真正的 MLE。 GAMLSS 的結果不同也就不足為奇了。 它是一個完全不同的統計模型:Generalized Additive Model。

還是不相信? 我們可以圍繞 MLE 繪制 2D 置信限圖,詳情請參閱 Meeker 和 Escobar 的書)。多維置信區域

這再次驗證了array([6.8820748596850905, 1.8553346917584836])是正確的答案,因為對數似然比參數空間中的任何其他點都低。 筆記:

>>> log(array([6.8820748596850905, 1.8553346917584836]))
array([ 1.92892018,  0.61806511])

順便說一句,MLE 擬合可能似乎與分布直方圖不太吻合。 考慮 MLE 的一種簡單方法是 MLE 是給定觀察數據最可能的參數估計。 它不需要在視覺上很好地擬合直方圖,這將是最小化均方誤差的東西。

順便說一句,您的數據似乎是leptokurtic 和左偏的,這意味着Weibull 分布可能不太適合您的數據。 試試,例如 Gompertz-Logistic,它將對數似然再提高大約 100。 在此處輸入圖片說明在此處輸入圖片說明 干杯!

我知道這是一個舊帖子,但我剛剛遇到了類似的問題,這個線程幫助我解決了它。 認為我的解決方案可能對像我這樣的其他人有幫助:

# Fit Weibull function, some explanation below
params = stats.exponweib.fit(data, floc=0, f0=1)
shape = params[1]
scale = params[3]
print 'shape:',shape
print 'scale:',scale

#### Plotting
# Histogram first
values,bins,hist = plt.hist(data,bins=51,range=(0,25),normed=True)
center = (bins[:-1] + bins[1:]) / 2.

# Using all params and the stats function
plt.plot(center,stats.exponweib.pdf(center,*params),lw=4,label='scipy')

# Using my own Weibull function as a check
def weibull(u,shape,scale):
    '''Weibull distribution for wind speed u with shape parameter k and scale parameter A'''
    return (shape / scale) * (u / scale)**(shape-1) * np.exp(-(u/scale)**shape)

plt.plot(center,weibull(center,shape,scale),label='Wind analysis',lw=2)
plt.legend()

一些幫助我理解的額外信息:

Scipy Weibull 函數可以接受四個輸入參數:(a,c)、loc 和 scale。 您想修復 loc 和第一個形狀參數 (a),這是通過 floc=0,f0=1 完成的。 擬合然后會給你參數 c 和比例,其中 c 對應於雙參數威布爾分布的形狀參數(通常用於風數據分析),比例對應於其比例因子。

從文檔:

exponweib.pdf(x, a, c) =
    a * c * (1-exp(-x**c))**(a-1) * exp(-x**c)*x**(c-1)

如果 a 為 1,則

exponweib.pdf(x, a, c) =
    c * (1-exp(-x**c))**(0) * exp(-x**c)*x**(c-1)
  = c * (1) * exp(-x**c)*x**(c-1)
  = c * x **(c-1) * exp(-x**c)

由此,與“風分析”威布爾函數的關系應該更清楚

我對您的問題很好奇,盡管這不是答案,但它將Matlab結果與您的結果以及使用leastsq的結果進行了leastsq ,這顯示了與給定數據的最佳相關性:

在此處輸入圖片說明

代碼如下:

import scipy.stats as s
import numpy as np
import matplotlib.pyplot as plt
import numpy.random as mtrand
from scipy.integrate import quad
from scipy.optimize import leastsq

## my distribution (Inverse Normal with shape parameter mu=1.0)
def weib(x,n,a):
    return (a / n) * (x / n)**(a-1) * np.exp(-(x/n)**a)

def residuals(p,x,y):
    integral = quad( weib, 0, 16, args=(p[0],p[1]) )[0]
    penalization = abs(1.-integral)*100000
    return y - weib(x, p[0],p[1]) + penalization

#
data = np.loadtxt("stack_data.csv")


x = np.linspace(data.min(), data.max(), 100)
n, bins, patches = plt.hist(data,bins=x, normed=True)
binsm = (bins[1:]+bins[:-1])/2

popt, pcov = leastsq(func=residuals, x0=(1.,1.), args=(binsm,n))

loc, scale = 1.58463497, 5.93030013
plt.plot(binsm,n)
plt.plot(x, weib(x, loc, scale),
         label='weib matlab, loc=%1.3f, scale=%1.3f' % (loc, scale), lw=4.)
loc, scale = s.exponweib.fit_loc_scale(data, 1, 1)
plt.plot(x, weib(x, loc, scale),
         label='weib stack, loc=%1.3f, scale=%1.3f' % (loc, scale), lw=4.)
plt.plot(x, weib(x,*popt),
         label='weib leastsq, loc=%1.3f, scale=%1.3f' % tuple(popt), lw=4.)

plt.legend(loc='upper right')
plt.show()

我遇到了同樣的問題,但發現在exponweib.fit中設置loc=0exponweib.fit泵以進行優化。 這就是@user333700's answer所需的全部內容。 我無法加載您的數據 - 您的數據鏈接指向圖像,而不是數據。 所以我對我的數據進行了測試:

擬合有問題(雙峰?)數據的分布圖

import scipy.stats as ss
import matplotlib.pyplot as plt
import numpy as np

N=30
counts, bins = np.histogram(x, bins=N)
bin_width = bins[1]-bins[0]
total_count = float(sum(counts))

f, ax = plt.subplots(1, 1)
f.suptitle(query_uri)

ax.bar(bins[:-1]+bin_width/2., counts, align='center', width=.85*bin_width)
ax.grid('on')
def fit_pdf(x, name='lognorm', color='r'):
    dist = getattr(ss, name)  # params = shape, loc, scale
    # dist = ss.gamma  # 3 params

    params = dist.fit(x, loc=0)  # 1-day lag minimum for shipping
    y = dist.pdf(bins, *params)*total_count*bin_width
    sqerror_sum = np.log(sum(ci*(yi - ci)**2. for (ci, yi) in zip(counts, y)))
    ax.plot(bins, y, color, lw=3, alpha=0.6, label='%s   err=%3.2f' % (name, sqerror_sum))
    return y

colors = ['r-', 'g-', 'r:', 'g:']

for name, color in zip(['exponweib', 't', 'gamma'], colors): # 'lognorm', 'erlang', 'chi2', 'weibull_min', 
    y = fit_pdf(x, name=name, color=color)

ax.legend(loc='best', frameon=False)
plt.show()

在這里和其他地方已經有一些答案。 Weibull 分布中的likt 和同一圖中的數據(使用 numpy 和 scipy)

我仍然花了一段時間才想出一個干凈的玩具示例,所以我認為發布它會很有用。

from scipy import stats
import matplotlib.pyplot as plt

#input for pseudo data
N = 10000
Kappa_in = 1.8
Lambda_in = 10
a_in = 1
loc_in = 0 

#Generate data from given input
data = stats.exponweib.rvs(a=a_in,c=Kappa_in, loc=loc_in, scale=Lambda_in, size = N)

#The a and loc are fixed in the fit since it is standard to assume they are known
a_out, Kappa_out, loc_out, Lambda_out = stats.exponweib.fit(data, f0=a_in,floc=loc_in)

#Plot
bins = range(51)
fig = plt.figure() 
ax = fig.add_subplot(1, 1, 1)
ax.plot(bins, stats.exponweib.pdf(bins, a=a_out,c=Kappa_out,loc=loc_out,scale = Lambda_out))
ax.hist(data, bins = bins , density=True, alpha=0.5)
ax.annotate("Shape: $k = %.2f$ \n Scale: $\lambda = %.2f$"%(Kappa_out,Lambda_out), xy=(0.7, 0.85), xycoords=ax.transAxes)
plt.show()

loc 和 scale 的順序在代碼中搞砸了:

plt.plot(x, weib(x, scale, loc))

比例參數應該放在第一位。

與此同時,有一個非常好的包裝:可靠性。 這是文檔:可靠性@ readthedocs

您的代碼簡單地變為:

from reliability.Fitters import Fit_Weibull_2P
...
wb = Fit_Weibull_2P(failures=data)
plt.show()

省去了很多麻煩,也可以制作漂亮的情節。

暫無
暫無

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

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