[英]Fitting lognormal distribution using Scipy vs Matlab
我正在嘗試使用Scipy擬合對數正態分布。 我之前已經使用Matlab完成了它,但由於需要將應用程序擴展到統計分析之外,我正在嘗試在Scipy中重現擬合值。
下面是我用來擬合數據的Matlab代碼:
% Read input data (one value per line)
x = [];
fid = fopen(file_path, 'r'); % reading is default action for fopen
disp('Reading network degree data...');
if fid == -1
disp('[ERROR] Unable to open data file.')
else
while ~feof(fid)
[x] = [x fscanf(fid, '%f', [1])];
end
c = fclose(fid);
if c == 0
disp('File closed successfully.');
else
disp('[ERROR] There was a problem with closing the file.');
end
end
[f,xx] = ecdf(x);
y = 1-f;
parmhat = lognfit(x); % MLE estimate
mu = parmhat(1);
sigma = parmhat(2);
這是合適的情節:
現在這是我的Python代碼,目的是實現相同的目標:
import math
from scipy import stats
from statsmodels.distributions.empirical_distribution import ECDF
# The same input is read as a list in Python
ecdf_func = ECDF(degrees)
x = ecdf_func.x
ccdf = 1-ecdf_func.y
# Fit data
shape, loc, scale = stats.lognorm.fit(degrees, floc=0)
# Parameters
sigma = shape # standard deviation
mu = math.log(scale) # meanlog of the distribution
fit_ccdf = stats.lognorm.sf(x, [sigma], floc=1, scale=scale)
這是使用Python代碼的適合度。
正如您所看到的,兩組代碼都能夠產生良好的擬合,至少在視覺上是這樣。
問題是估計的參數mu和sigma存在巨大差異。
來自Matlab:mu = 1.62 sigma = 1.29。 來自Python:mu = 2.78 sigma = 1.74。
為什么會有這樣的差異?
注意:我仔細檢查了兩組數據是否完全相同 。 相同數量的點,相同的分布。
非常感謝您的幫助! 提前致謝。
其他信息:
import scipy
import numpy
import statsmodels
scipy.__version__
'0.9.0'
numpy.__version__
'1.6.1'
statsmodels.__version__
'0.5.0.dev-1bbd4ca'
版本的Matlab是R2011b。
版:
如下面的答案所示,故障在於Scipy 0.9。 我能夠使用Scipy 11.0從Matlab重現mu和sigma結果。
更新Scipy的簡便方法是:
pip install --upgrade Scipy
如果你沒有pip(你應該!):
sudo apt-get install pip
scipy 0.9.0中的fit
方法中存在一個錯誤,該錯誤已在scipy的更高版本中修復。
下面腳本的輸出應該是:
Explicit formula: mu = 4.99203450, sig = 0.81691086
Fit log(x) to norm: mu = 4.99203450, sig = 0.81691086
Fit x to lognorm: mu = 4.99203468, sig = 0.81691081
但是scipy 0.9.0就是這樣
Explicit formula: mu = 4.99203450, sig = 0.81691086
Fit log(x) to norm: mu = 4.99203450, sig = 0.81691086
Fit x to lognorm: mu = 4.23197270, sig = 1.11581240
以下測試腳本顯示了獲得相同結果的三種方法:
import numpy as np
from scipy import stats
def lognfit(x, ddof=0):
x = np.asarray(x)
logx = np.log(x)
mu = logx.mean()
sig = logx.std(ddof=ddof)
return mu, sig
# A simple data set for easy reproducibility
x = np.array([50., 50, 100, 200, 200, 300, 500])
# Explicit formula
my_mu, my_sig = lognfit(x)
# Fit a normal distribution to log(x)
norm_mu, norm_sig = stats.norm.fit(np.log(x))
# Fit the lognormal distribution
lognorm_sig, _, lognorm_expmu = stats.lognorm.fit(x, floc=0)
print "Explicit formula: mu = %10.8f, sig = %10.8f" % (my_mu, my_sig)
print "Fit log(x) to norm: mu = %10.8f, sig = %10.8f" % (norm_mu, norm_sig)
print "Fit x to lognorm: mu = %10.8f, sig = %10.8f" % (np.log(lognorm_expmu), lognorm_sig)
在std中使用選項ddof=1
。 開發。 計算使用無偏方差估計:
In [104]: x
Out[104]: array([ 50., 50., 100., 200., 200., 300., 500.])
In [105]: lognfit(x, ddof=1)
Out[105]: (4.9920345004312647, 0.88236457185021866)
在matlab的lognfit文檔中有一條說明,即當不使用審查時,lognfit使用方差的無偏估計的平方根計算sigma。 這對應於在上面的代碼中使用ddof = 1。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.