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

问题描述 投票:0回答:5

我正在尝试使用 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新手,所以即使我尝试阅读文档,我也无法使其工作。任何帮助将不胜感激。

python-3.x scipy curve-fitting
5个回答
8
投票

我不知道这是否是“正确”的做事方式,但我通常将函数包装在一个类中,以便我可以从

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)

这种方法避免使用全局参数,这通常被认为是邪恶的


5
投票

我也推荐 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 还有许多其他用于曲线拟合的优秀功能,包括构建复杂模型和评估置信区间。


2
投票

一个非常简单的方法是使用 functools 中的

partial
函数。在这种情况下,您所要做的就是以下操作。在这种情况下,必须定义
b
be,否则我相信
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)

1
投票

您可以将

b
定义为 fit 函数内的全局变量。

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.]

1
投票

更新: 很抱歉发布未经测试的代码。正如 @mr-t 所指出的,代码确实抛出了一个错误。看起来,curve_fit函数的kwargs参数是设置

leastsq
least_squares
函数的关键字参数,而不是fit函数本身的关键字参数。

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

leastsq
函数。

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


b=10    
leastsq(fitfun,x0=1,args=(xdata,ydata,b))
© www.soinside.com 2019 - 2024. All rights reserved.