【问题标题】:Is there a way to get the error in fitting parameters from scipy.stats.norm.fit?有没有办法从 scipy.stats.norm.fit 中获取拟合参数的错误?
【发布时间】:2018-08-14 06:45:57
【问题描述】:

我有一些数据,我使用 scipy.stats.normal 对象拟合函数拟合正态分布,如下所示:

import numpy as np                                                                                                                                                                                                                       
import matplotlib.pyplot as plt                                                                                                                                                                                                          
from scipy.stats import norm                                                                                                                                                                                                             
import matplotlib.mlab as mlab                                                                                                                                                                                                           

x = np.random.normal(size=50000)                                                                                                                                                                                                         

fig, ax = plt.subplots()                                                                                                                                                                                                                 

nbins = 75                                                                                                                                                                                                                               
mu, sigma = norm.fit(x)                                                                                                                                                                                                                  
n, bins, patches = ax.hist(x,nbins,normed=1,facecolor = 'grey', alpha = 0.5, label='before');                                                                                                                                            
y0 = mlab.normpdf(bins, mu, sigma) # Line of best fit                                                                                                                                                                                    
ax.plot(bins,y0,'k--',linewidth = 2, label='fit before')                                                                                                                                                                                 
ax.set_title('$\mu$={}, $\sigma$={}'.format(mu, sigma))                                                                                                                                                                                  

plt.show()                                                                                                                                                                                                                               

我现在想提取拟合的 mu 和 sigma 值中的不确定性/误差。我该怎么办?

【问题讨论】:

    标签: python statistics curve-fitting gaussian data-fitting


    【解决方案1】:

    您可以使用scipy.optimize.curve_fit: 该方法不仅返回估计的最优值 参数,还有对应的协方差矩阵:

    popt : 数组

    参数的最优值使得残差平方和 f(xdata, *popt) - ydata 被最小化

    pcov:二维数组

    popt 的估计协方差。对角线提供参数估计的方差。要计算参数的一个标准差误差,请使用 perr = np.sqrt(np.diag(pcov))。

    如上所述,sigma 参数如何影响估计的协方差取决于 absolute_sigma 参数。

    如果解决方案中的雅可比矩阵没有满秩,则 'lm' 方法返回一个填充有 np.inf 的矩阵,另一方面,'trf' 和 'dogbox' 方法使用 Moore-Penrose 伪逆计算协方差矩阵。

    您可以从协方差矩阵的对角元素的平方根计算参数的标准偏差误差如下:

    import numpy as np 
    import matplotlib.pyplot as plt
    from scipy.stats import norm 
    from scipy.optimize import curve_fit
    
    x = np.random.normal(size=50000)
    fig, ax = plt.subplots() 
    nbins = 75
    n, bins, patches = ax.hist(x,nbins, density=True, facecolor = 'grey', alpha = 0.5, label='before'); 
    
    centers = (0.5*(bins[1:]+bins[:-1]))
    pars, cov = curve_fit(lambda x, mu, sig : norm.pdf(x, loc=mu, scale=sig), centers, n, p0=[0,1])
    
    ax.plot(centers, norm.pdf(centers,*pars), 'k--',linewidth = 2, label='fit before') 
    ax.set_title('$\mu={:.4f}\pm{:.4f}$, $\sigma={:.4f}\pm{:.4f}$'.format(pars[0],np.sqrt(cov[0,0]), pars[1], np.sqrt(cov[1,1 ])))
    
    plt.show()
    

    这导致以下情节:

    【讨论】:

    • 请注意,此处报告的不确定性完全是由于将数据采样到 75 个 bin 中。除了其他任意的分箱之外,没有噪声源或非正态分布。
    • @MNewville 那么,norm.fit 不会受到这些不确定性的影响吗?除了报告这些不确定性之外,curve_fitnorm.fit 有何不同?
    • @AlwaysLearningForever 。我认为我之前的评论是不正确的——存在自然分布,并且有足够多的 bin 数量,质心和宽度的不确定性将稳定到非零值。对于 norm.fit 的作用:我不是 100% 确定,但我相信 scipy.stats.norm.fit() 使用 Nelder-Mead 进行拟合,而 curve_fit 使用 Levenberg-Marquardt。我不知道scipy.stats.norm.fit() 是否会尝试估计不确定性,但我怀疑不会。
    【解决方案2】:

    另请参阅 lmfit (https://github.com/lmfit/lmfit-py),它提供了更简单的界面并报告拟合变量的不确定性。要将数据拟合到正态分布,请参阅http://lmfit.github.io/lmfit-py/builtin_models.html#example-1-fit-peak-data-to-gaussian-lorentzian-and-voigt-profiles

    并使用类似的东西

    from lmfit.models import GaussianModel
    
    model = GaussianModel()
    
    # create parameters with initial guesses:
    params = model.make_params(center=9, amplitude=40, sigma=1)  
    
    result = model.fit(ydata, params, x=xdata)
    print(result.fit_report())
    

    报告将包括 1-sigma 错误,例如

    [[Variables]]
        sigma:       1.23218358 +/- 0.007374 (0.60%) (init= 1.0)
        center:      9.24277047 +/- 0.007374 (0.08%) (init= 9.0)
        amplitude:   30.3135620 +/- 0.157126 (0.52%) (init= 40.0)
        fwhm:        2.90157055 +/- 0.017366 (0.60%)  == '2.3548200*sigma'
        height:      9.81457817 +/- 0.050872 (0.52%)  == '0.3989423*amplitude/max(1.e-15, sigma)'
    

    【讨论】:

    • 您提供的示例代码中使用什么方法确定初始参数值?
    • @JamesPhillips :我查看了数据(甚至没有在此处发布,而是在 lmfit 示例中)并猜测了。 Lmfit 的 GaussianModel 实际上有一个 guess 方法来帮助猜测中心、幅度和 sigma——链接的示例使用该方法。 scipy 或其他库中的峰值查找实用程序也可用于识别峰值中心。而且:对于孤立的高斯峰,您不需要在初始猜测中如此接近以使拟合收敛。
    • 在这种情况下,您的猜测确实有效。
    猜你喜欢
    • 2011-03-19
    • 2016-08-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多