2017-05-23 87 views
2

我想對我已經分箱的數據做一個對數正態分佈。條形圖看起來像這樣:enter image description here適合對數正態分佈到已分箱的數據python

不幸的是,當我嘗試使用標準lognorm.pdf()時,擬合分佈的形狀非常不同。我想這是因爲我的數據已經被分類了。下面的代碼:

times, data, bin_points = ReadHistogramFile(filename) 

xmin = 200 
xmax = 800 
x = np.linspace(xmin, xmax, 1000) 
shape, loc, scale = stats.lognorm.fit(data, floc=0) 
pdf = stats.lognorm.pdf(x, shape, loc=loc, scale=scale) 

area=data.sum() 
plt.bar(bars, data, width=10, color='b') 
plt.plot(x*area, pdf, 'k') 

這裏的擬合分佈的樣子: enter image description here 顯然有什麼東西與縮放也是錯誤的。儘管如此,我不那麼在意。我的主要問題是,分佈的形狀。這可能會重複到:this question但我無法找到正確的解決方案。我嘗試了它,並且仍然得到了與上述相似的形狀。謝謝你的幫助!

更新: 通過使用curve_fit()我能夠得到一些適合。但我還不滿意。我想要有原始的垃圾桶,而不是統一垃圾桶。此外,我不確定,究竟發生了什麼,如果沒有更好的選擇。下面的代碼:

def normalize_integral(data, bin_size): 
normalized_data = np.zeros(size(data)) 
print bin_size 
sum = data.sum() 
integral = bin_size*sum 
for i in range(0, size(data)-1): 
    normalized_data[i] = data[i]/integral 

print 'integral:', normalized_data.sum()*bin_size 
return normalized_data 



def pdf(x, mu, sigma): 
"""pdf of lognormal distribution""" 

return (np.exp(-(np.log(x) - mu)**2/(2 * sigma**2))/(x * sigma * np.sqrt(2 * np.pi))) 


bin_points=np.linspace(280.5, 1099.55994, len(bin_points)) 
data=[9.78200000e+03 1.15120000e+04 1.18000000e+04 1.79620000e+04 2.76980000e+04 2.78260000e+04 3.35460000e+04 3.24260000e+04 3.16500000e+04 3.30820000e+04 4.84560000e+04 5.86500000e+04 6.34220000e+04 5.11880000e+04 5.13180000e+04 4.74320000e+04 4.35420000e+04 4.13400000e+04 3.60880000e+04 2.96900000e+04 2.66640000e+04 2.58720000e+04 2.57560000e+04 2.20960000e+04 1.46880000e+04 9.97200000e+03 5.74200000e+03 3.52000000e+03 2.74600000e+03 2.61800000e+03 1.50000000e+03 7.96000000e+02 5.40000000e+02 2.98000000e+02 2.90000000e+02 2.22000000e+02 2.26000000e+02 1.88000000e+02 1.20000000e+02 5.00000000e+01 5.40000000e+01 5.80000000e+01 5.20000000e+01 2.00000000e+01 2.80000000e+01 6.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] 
normalized_data_unitybins = normalize_integral(data,1) 


plt.figure(figsize=(9,4)) 
ax1=plt.subplot(121) 
ax2=plt.subplot(122) 
ax2.bar(unity_bins, normalized_data_unitybins, width=1, color='b') 
fitParams, fitCov = curve_fit(pdf, unity_bins, normalized_data_unitybins, p0=[1,1],maxfev = 1000000) 
fitData=pdf(unity_bins, *fitParams) 
ax2.plot(unity_bins, fitData,'g-') 

ax1.bar(bin_points, normalized_data_unitybins, width=10, color='b') 
fitParams, fitCov = curve_fit(pdf, bin_points, normalized_data_unitybins, p0=[1,1],maxfev = 1000000) 
fitData=pdf(bin_points, *fitParams) 
ax1.plot(bin_points, fitData,'g-') 

enter image description here

+0

這看起來像'pdf'的尾部。嘗試縮小x軸 –

+0

對於範圍[0,1000],它看起來也是一樣的。 – aces

+0

'shape','loc'和'scale'的值是什麼? –

回答

2

至於你提到,你不能對分級數據使用lognorm.fit。所以你所要做的就是從直方圖中恢復原始數據。顯然這不是'無損',越多越好。

示例代碼與一些生成的數據:

import numpy as np 
import scipy.stats as stats 
import matplotlib.pylab as plt 


# generate some data 
ln = stats.lognorm(0.4,scale=100) 
data = ln.rvs(size=2000) 

counts, bins, _ = plt.hist(data, bins=50) 
# note that the len of bins is 51, since it contains upper and lower limit of every bin 

# restore data from histogram: counts multiplied bin centers 
restored = [[d]*int(counts[n]) for n,d in enumerate((bins[1:]+bins[:-1])/2)] 
# flatten the result 
restored = [item for sublist in restored for item in sublist] 

print stats.lognorm.fit(restored, floc=0) 

dist = stats.lognorm(*stats.lognorm.fit(restored, floc=0)) 
x = np.arange(1,400) 
y = dist.pdf(x) 

# the pdf is normalized, so we need to scale it to match the histogram 
y = y/y.max() 
y = y*counts.max() 

plt.plot(x,y,'r',linewidth=2) 
plt.show() 

fitted histogram