【问题标题】:python SciPy curve_fit with np.exp returns with pcov = infpython SciPy curve_fit with np.exp 返回 pcov = inf
【发布时间】:2020-04-27 14:01:49
【问题描述】:

我正在尝试使用 scipy.optimize.curve_fit 优化指数拟合。但结果并不好。我的代码是:

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

# xdata and data is obtain from another dataframe and their type is nparray

xdata =[36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70 ,71,72]
ydata = [4,4,4,6,6,13,22,22,26,28,38,48,55,65,65,92,112,134,171,210,267,307,353,436,669,669,818,1029,1219,1405,1617,1791,2032,2032,2182,2298,2389]

popt, pcov = curve_fit(func, xdata, ydata)
plt.plot(xdata, func(xdata, *popt), 'r-', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt))

plt.scatter(xdata, ydata, s=1)
plt.show()

然后我得到这样的结果:

enter image description here

结果表明:

pcov = [[inf inf inf] [inf inf inf] [inf inf inf]]
popt = [1  1  611.83784]

我不知道如何让我的曲线很好地贴合。你能和我打招呼吗?谢谢!

【问题讨论】:

    标签: python exponential scipy-optimize


    【解决方案1】:

    对指数函数进行拟合非常困难,因为指数的微小变化会导致结果的巨大差异。优化器在多个数量级上进行优化,与曲线上方的误差相比,原点附近的误差的权重不同。

    处理这个问题的最简单方法是使用转换将指数数据转换为一条线:

    y' = np.log(y)
    

    然后,您无需使用更高级(且更慢)的 curve_fit,只需使用 numpy 的 polyfit 函数并拟合一条线即可。如果您愿意,可以将数据转换回线性空间进行分析。在这里,我编辑了您的代码以使用 np.polyfit 进行拟合,您可以看到拟合是明智的。

    import numpy as np
    import matplotlib.pyplot as plt
    # from scipy.optimize import curve_fit
    
    # def func(x, a, b, c):
    #   return a * np.exp(-b * x) + c
    
    # xdata and data is obtain from another dataframe and their type is nparray
    
    xdata = np.array([36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70 ,71,72])
    ydata = np.array([4,4,4,6,6,13,22,22,26,28,38,48,55,65,65,92,112,134,171,210,267,307,353,436,669,669,818,1029,1219,1405,1617,1791,2032,2032,2182,2298,2389])
    
    # popt, pcov = curve_fit(func, xdata, ydata)
    # plt.plot(xdata, func(xdata, *popt), 'r-', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt))
    
    # Fit a line (deg=1)
    P, pcov = np.polyfit(xdata, np.log(ydata), deg=1, cov=True)
    print(pcov)
    plt.scatter(xdata, ydata, s=1)
    plt.plot(xdata, np.exp(P[0]*xdata + P[1]), 'r-')
    
    plt.legend()
    plt.show()
    

    【讨论】:

      【解决方案2】:

      该方法没有找到最佳点。要尝试的一件事是更改初始猜测,使 b 开始为负数,因为它从您的数据中看起来 b 必须为负数,以便 func 适合它。此外,从curve_fit 的文档中,如果未指定,初始猜测默认为 1。一个好的初步猜测是:

      popt, pcov = curve_fit(func, xdata, ydata, p0=[1, -0.05, 1])
      

      这给了

      popt                                                                                                                                                                                                      
      array([ 1.90782987e+00, -1.01639857e-01, -1.73633728e+02])
      
      pcov                                                                                                                                                                                                           
      array([[ 1.08960274e+00,  7.93580944e-03, -5.24526701e+01],
             [ 7.93580944e-03,  5.79450721e-05, -3.74693994e-01],
             [-5.24526701e+01, -3.74693994e-01,  3.34388178e+03]])
      

      还有剧情

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-26
        • 2013-11-03
        • 2014-09-05
        • 2013-07-30
        • 1970-01-01
        • 2019-02-26
        • 1970-01-01
        • 2016-03-08
        相关资源
        最近更新 更多