【问题标题】:Pass tuple as input argument for scipy.optimize.curve_fit将元组作为 scipy.optimize.curve_fit 的输入参数传递
【发布时间】:2013-08-22 00:01:20
【问题描述】:

我有以下代码:

import numpy as np
from scipy.optimize import curve_fit


def func(x, p): return p[0] + p[1] + x


popt, pcov = curve_fit(func, np.arange(10), np.arange(10), p0=(0, 0)) 

它会引发 TypeError: func() 只需要 2 个参数(给定 3 个)。好吧,这听起来很公平 - curve_fit 将 (0, 0) 解压缩为两个标量输入。所以我尝试了这个:

popt, pcov = curve_fit(func, np.arange(10), np.arange(10), p0=((0, 0),))

再次,它说:ValueError: object too deep for desired array

如果我将其保留为默认值(未指定 p0):

popt, pcov = curve_fit(func, np.arange(10), np.arange(10))  

它会引发IndexError: invalid index to scalar variable。显然,它只是给函数一个p的标量。

我可以让 def func(x, p1, p2): return p1 + p2 + x 让它工作,但在更复杂的情况下,代码会显得冗长和混乱。如果这个问题有更清洁的解决方案,我会很高兴的。

谢谢!

【问题讨论】:

    标签: python numpy scipy curve-fitting


    【解决方案1】:

    问题

    当使用curve_fit 时,您必须明确说明拟合参数的数量。做类似的事情:

    def f(x, *p):
        return sum( [p[i]*x**i for i in range(len(p))] )
    

    会很棒,因为它是一个通用的 n 阶多项式拟合函数,但不幸的是,在我的 SciPy 0.12.0 中,它提出了:

    ValueError: Unable to determine number of fit parameters.
    

    解决方案

    所以你应该这样做:

    def f_1(x, p0, p1):
        return p0 + p1*x
    
    def f_2(x, p0, p1, p2):
        return p0 + p1*x + p2*x**2
    

    等等……

    然后您可以使用p0 参数调用:

    curve_fit(f_1, xdata, ydata, p0=(0,0))
    

    【讨论】:

    • 其实你可以做一般的n阶多项式。只需指定p0=np.ones(degree) 即可在调用curve_fit 时选择您想要的程度
    【解决方案2】:

    您可以定义返回其他函数的函数(参见Passing additional arguments using scipy.optimize.curve_fit?

    工作示例:

    import numpy as np
    import random
    from scipy.optimize import curve_fit
    from matplotlib import pyplot as plt
    import math
    
    def funToFit(x):
        return 0.5+2*x-3*x*x+0.2*x*x*x+0.1*x*x*x*x
    
    
    xx=[random.uniform(1,5) for i in range(30)]
    yy=[funToFit(xx[i])+random.uniform(-1,1) for i in range(len(xx))]
    
    
    a=np.zeros(5)
    def make_func(numarg):
        def func(x,*a):
            ng=numarg
            v=0
            for i in range(ng):
                v+=a[i]*np.power(x,i)
            return v
        return func
    
    leastsq, covar = curve_fit(make_func(len(a)),xx,yy,tuple(a))
    print leastsq
    def fFited(x):
        v=0
        for i in range(len(leastsq)):
            v+=leastsq[i]*np.power(x,i)
        return v
    
    
    xfine=np.linspace(1,5,200)
    plt.plot(xx,yy,".")
    plt.plot(xfine,fFited(xfine))
    plt.show()
    

    【讨论】:

      【解决方案3】:

      scipy.optimize.curve_fit

      scipy.optimize.curve_fit(f, xdata, ydata, p0=None, sigma=None, **kw)

      Use non-linear least squares to fit a function, f, to data.
      
      Assumes ydata = f(xdata, *params) + eps
      

      解释这个想法

      要拟合的函数应仅采用标量*p0)。 请记住,拟合的结果取决于初始化参数。

      工作示例

      import numpy as np
      from scipy.optimize import curve_fit
      import matplotlib.pyplot as plt
      
      def func(x, a0, a1):
          return a0 + a1 * x
      
      x, y = np.arange(10), np.arange(10) + np.random.randn(10)/10
      popt, pcov = curve_fit(func, x, y, p0=(1, 1))
      
      # Plot the results
      plt.title('Fit parameters:\n a0=%.2e a1=%.2e' % (popt[0], popt[1]))
      # Data
      plt.plot(x, y, 'rx')
      # Fitted function
      x_fine = np.linspace(x[0], x[-1], 100)
      plt.plot(x_fine, func(x_fine, popt[0], popt[1]), 'b-')
      plt.savefig('Linear_fit.png')
      plt.show()
      

      【讨论】:

      • 这种方法可以扩展到仅包含 2 个值的元组之外吗? 3、4、5等呢?
      【解决方案4】:

      不确定这是否更简洁,但至少现在向拟合函数添加更多参数更容易。也许人们甚至可以从中找到更好的解决方案。

      import numpy as np
      from scipy.optimize import curve_fit
      
      
      def func(x, p): return p[0] + p[1] * x
      
      def func2(*args):
          return func(args[0],args[1:])
      
      popt, pcov = curve_fit(func2, np.arange(10), np.arange(10), p0=(0, 0))
      print popt,pcov
      

      编辑:这对我有用

      import numpy as np
      from scipy.optimize import curve_fit
      
      def func(x, *p): return p[0] + p[1] * x
      
      popt, pcov = curve_fit(func, np.arange(10), np.arange(10), p0=(0, 0))
      print popt,pcov
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-17
        • 2011-02-22
        • 2020-12-23
        • 2016-02-07
        相关资源
        最近更新 更多