本文介绍了使用Scipy与Matlab拟合对数正态分布的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Scipy拟合对数正态分布.我之前已经使用Matlab进行过此操作,但是由于需要将应用程序扩展到统计分析之外,因此我正在尝试在Scipy中重现拟合值.

I am trying to fit a lognormal distribution using Scipy. I've already done it using Matlab before but because of the need to extend the application beyond statistical analysis, I am in the process of trying to reproduce the fitted values in Scipy.

下面是我用来拟合数据的Matlab代码:

Below is the Matlab code I used to fit my data:

% 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代码,旨在实现相同的目标:

Now here's my Python code with the aim of achieving the same:

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代码的合适选择.

Here's the fit using the Python code.

如您所见,至少在视觉上,两组代码都能产生良好的契合度.

As you can see, both sets of code are capable of producing good fits, at least visually speaking.

问题在于,估计参数mu和sigma之间存在巨大差异.

Problem is that there is a huge difference in the estimated parameters mu and sigma.

来自Matlab:mu = 1.62 sigma = 1.29.在Python中:mu = 2.78 sigma = 1.74.

From Matlab: mu = 1.62 sigma = 1.29.From Python: mu = 2.78 sigma = 1.74.

为什么会有这样的区别?

Why is there such a difference?

注意:我已经仔细检查了所拟合的两组数据完全相同.点数相同,分布相同.

Note: I have double checked that both sets of data fitted are exactly the same. Same number of points, same distribution.

非常感谢您的帮助!预先感谢.

Your help is much appreciated! Thanks in advance.

其他信息:

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.

Version of Matlab is R2011b.

版本:

如下面的答案所示,故障出在Scipy 0.9.我可以使用Scipy 11.0从Matlab复制mu和sigma结果.

As demonstrated in the answer below, the fault lies with Scipy 0.9. I am able to reproduce the mu and sigma results from Matlab using Scipy 11.0.

更新Scipy的简单方法是:

An easy way to update your Scipy is:

pip install --upgrade Scipy

如果您没有点子(应该!):

If you don't have pip (you should!):

sudo apt-get install pip

推荐答案

scipy 0.9.0中的fit方法中有一个错误,已在更高版本的scipy中修复.

There is a bug in the fit method in scipy 0.9.0 that has been fixed in later versions of 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,是

but with scipy 0.9.0, it is

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

以下测试脚本显示了三种获得相同结果的方法:

The following test script shows three ways to get the same results:

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)

在标准选项中带有选项ddof=1.开发.计算以使用无偏方差估计:

With the option ddof=1 in the std. dev. calculation to use the unbiased variance estimation:

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.

There is a note in matlab's lognfit documentation that says when censoring is not used, lognfit computes sigma using the square root of the unbiased estimator of the variance. This corresponds to using ddof=1 in the above code.

这篇关于使用Scipy与Matlab拟合对数正态分布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 10:57