使用scipy.optimize.curve_fit时如何将参数传递给拟合函数

时间:2018-04-13 09:20:37

标签: python-3.x scipy curve-fitting

我正在尝试使用scipy.optimize.curve_fit来拟合我所拥有的一些数据。 我的契合函数是:

def fitfun(x, a):
    return np.exp(a*(x - b))

我想要的是将a定义为拟合参数,将b定义为根据我想要拟合的数据而变化的参数。这意味着对于一组数据,我希望拟合函数:np.exp(a*(x - 10))而对于另一组我想要拟合函数np.exp(a*(x - 20))。原则上,我希望参数b作为任何值传入。

我目前正在调用curve_fit的方式是:

coeffs, coeffs_cov = curve_fit(fitfun, xdata, ydata)

但我想要的是这样的:

b=10     
coeffs, coeffs_cov = curve_fit(fitfun(b), xdata, ydata)
b=20     
coeffs2, coeffs_cov2 = curve_fit(fitfun(b), xdata, ydata)

因此,我得到两个案例的系数a(b = 10和b = 20)。

我是python的新手所以即使我尝试阅读文档,也无法使其工作。任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:3)

我还建议lmfit(http://lmfit.github.io/lmfit-py/)及其针对此类问题的Model类。 Lmfit为曲线拟合和优化问题提供了更高级别的抽象。

使用lmfit,模型中的每个参数都成为一个可以固定,自由变化或给定上下界而不改变拟合函数的对象。此外,您可以定义多个"独立变量"对于任何型号。

这给你两种可能的方法。首先,定义参数并修复b

from lmfit import Model
def fitfun(x, a, b):
    return np.exp(a*(x - b))

# turn this model function into a Model:
mymodel = Model(fitfun)

# create parameters with initial values.  Note that parameters are 
# **named** according to the arguments of your model function:
params = mymodel.make_params(a=1, b=10)

# tell the 'b' parameter to not vary during the fit
params['b'].vary = False

# do fit
result = mymodel.fit(ydata, params, x=xdata)
print(result.fit_report())

params在拟合中没有改变(更新的参数在result.params中),所以为了适应另一组数据,您可以这样做:

params['b'].value = 20  #  Note that vary is still False
result2 = mymodel.fit(ydata2, params, x=xdata2)

另一种方法是将b定义为一个独立变量:

mymodel = Model(fitfun, independent_vars=['x', 'b'])

params = mymodel.make_params(a=1)
result = model.fit(ydata, params, x=xdata, b=10)

Lmfit还有许多其他很好的曲线拟合功能,包括组合复杂模型和评估置信区间。

答案 1 :(得分:2)

我不知道这是否是“正确的”做事方式,但我通常将我的函数包装在一个类中,以便我可以从self访问参数。您的示例将如下所示:

class fitClass:

    def __init__(self):
        pass

    def fitfun(self, x, a):
        return np.exp(a*(x - self.b))

inst = fitClass()

inst.b = 10
coeffs, coeffs_cov = curve_fit(inst.fitfun, xdata, ydata)

inst.b = 20
coeffs, coeffs_cov = curve_fit(inst.fitfun, xdata, ydata)

这种方法避免使用全局参数,generally considered evil

答案 2 :(得分:2)

您可以在fit函数中将b定义为全局变量。

from scipy.optimize import curve_fit

def fitfun(x, a):
    global b
    return np.exp(a*(x - b))

xdata = np.arange(10)

#first sample data set
ydata = np.exp(2 * (xdata - 10))

b = 10
coeffs, coeffs_cov = curve_fit(fitfun, xdata, ydata)
print(coeffs)

#second sample data set
ydata = np.exp(5 * (xdata - 20))

b = 20
coeffs, coeffs_cov = curve_fit(fitfun, xdata, ydata)
print(coeffs)

输出:

[2.]
[5.]

答案 3 :(得分:1)

更新: 抱歉发布未经测试的代码。正如@ mr-t所指出的,代码确实会引发错误。看来,curve_fit函数的kwargs参数是设置var a = 99.99; var b = 99.9999; var precision = 100; console.log(a, Math.round(a), Math.round(a * precision) / precision); console.log(b, Math.round(b), Math.round(b * precision) / precision);leastsq函数的关键字参数,而不是fit函数本身的关键字参数。

在这种情况下,除了其他人提出的答案之外,另一种可能的解决方案是重新定义fit函数以返回错误并直接调用允许传递参数的least_squares函数。

leastsq

答案 4 :(得分:0)

一种非常简单的方法是使用 functools 中的 partial 函数。在这种情况下,您只需执行以下操作。在这种情况下,b 必须定义,否则我相信 scipy.optimize.curvefit 除了 a

外还会尝试优化 b
from functools import partial

def fitfun(x, a, b):
    return np.exp(a*(x - b))

fitfun10 = partial(fitfun, b=10)
coeffs, coeffs_cov = curve_fit(fitfun10, xdata, ydata)

fitfun20 = partial(fitfun, b=20)
coeffs2, coeffs_cov2 = curve_fit(fitfun20, xdata, ydata)