【问题标题】:scipy.optimize.curve_fit unable to fit shifted skewed gaussian curvescipy.optimize.curve_fit 无法拟合偏移的偏斜高斯曲线
【发布时间】:2013-03-14 03:47:34
【问题描述】:

我正在尝试使用 scipy 的 curve_fit 函数拟合一条倾斜和移动的高斯曲线,但我发现在某些条件下拟合效果很差,通常让我接近或完全是一条直线。

以下代码源自curve_fit 文档。提供的代码是用于测试目的的任意数据集,但可以很好地显示问题。

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import math as math
import scipy.special as sp

#def func(x, a, b, c):
#    return a*np.exp(-b*x) + c

def func(x, sigmag, mu, alpha, c,a):
    #normal distribution
    normpdf = (1/(sigmag*np.sqrt(2*math.pi)))*np.exp(-(np.power((x-mu),2)/(2*np.power(sigmag,2))))
    normcdf = (0.5*(1+sp.erf((alpha*((x-mu)/sigmag))/(np.sqrt(2)))))
    return 2*a*normpdf*normcdf + c

x = np.linspace(0,100,100)
y = func(x, 10,30, 0,0,1)
yn = y + 0.001*np.random.normal(size=len(x))

popt, pcov = curve_fit(func, x, yn,) #p0=(9,35,0,9,1))

y_fit= func(x,popt[0],popt[1],popt[2],popt[3],popt[4])

plt.plot(x,yn)
plt.plot(x,y_fit)

当我将高斯从零移得太远(使用mu)时,问题似乎出现了。我已经尝试给出初始值,即使是那些与我的原始函数相同的值,但它并没有解决问题。对于 mu=10 的值,curve_fit 工作得很好,但如果我使用 mu>=30 它不再适合数据。

【问题讨论】:

    标签: python scipy gaussian


    【解决方案1】:

    给出最小化的起点通常会产生奇迹。尝试给最小化器一些关于最大值位置和曲线宽度的信息:

    popt, pcov = curve_fit(func, x, yn, p0=(1./np.std(yn), np.argmax(yn) ,0,0,1))
    

    使用sigma=10mu=50 更改代码中的这一行会产生

    【讨论】:

    • 好的,现在情况开始好转一些。我想我有点高估了 curve_fit 算法,并且期望过高。我现在手动将值停放,然后将它们插入curve_fit并获得不错的结果。干杯。
    【解决方案2】:

    你可以多次调用curve_fit随机初始猜测,选择误差最小的参数。

    import numpy as np
    from scipy.optimize import curve_fit
    import matplotlib.pyplot as plt
    import math as math
    import scipy.special as sp
    
    def func(x, sigmag, mu, alpha, c,a):
        #normal distribution
        normpdf = (1/(sigmag*np.sqrt(2*math.pi)))*np.exp(-(np.power((x-mu),2)/(2*np.power(sigmag,2))))
        normcdf = (0.5*(1+sp.erf((alpha*((x-mu)/sigmag))/(np.sqrt(2)))))
        return 2*a*normpdf*normcdf + c
    
    x = np.linspace(0,100,100)
    y = func(x, 10,30, 0,0,1)
    yn = y + 0.001*np.random.normal(size=len(x))
    
    results = []
    for i in xrange(50):
        p = np.random.randn(5)*10
        try:
            popt, pcov = curve_fit(func, x, yn, p)
        except:
            pass
        err = np.sum(np.abs(func(x, *popt) - yn))
        results.append((err, popt))
        if err < 0.1:
            break
    
    err, popt = min(results, key=lambda x:x[0])
    y_fit= func(x, *popt)
    
    plt.plot(x,yn)
    plt.plot(x,y_fit)
    print len(results)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-12
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 2014-01-02
      • 2012-06-12
      • 2021-10-14
      • 1970-01-01
      相关资源
      最近更新 更多