在python中只拟合多参数函数的一个参数

pgvzfuti  于 2023-01-04  发布在  Python
关注(0)|答案(7)|浏览(186)

在python中,我有一个函数,它有很多参数,我想让这个函数适合一个数据集,但是只使用一个参数,剩下的参数我想自己提供,下面是一个例子:

def func(x,a,b):
   return a*x*x + b

for b in xrange(10):
   popt,pcov = curve_fit(func,x1,x2)

在这里我希望只对a进行拟合,参数b取循环变量的值,如何实现呢?

lc8prwob

lc8prwob1#

如果你愿意/能够编辑原始函数,有一个更简单的选项。
将您的函数重新定义为:

def func(x,a):
    return a*x*x + b

然后你可以简单地把它放在参数B的循环中:

for b in xrange(10):
   popt,pcov = curve_fit(func, x1, x2)

警告:函数需要在调用它的同一脚本中定义,这样才能正常工作。

pxq42qpu

pxq42qpu2#

Scipy的curve_fit有三个位置参数,func,xdata和ydata,所以另一种方法(使用函数 Package 器)是将'B'作为xdata(即自变量),方法是构建一个矩阵,其中包含原始xdata(x1)和固定参数b的第二列。
假设x1和x2是数组:

def func(xdata,a):
   x, b = xdata[:,0], xdata[:,1]  # Extract your x and b
   return a*x*x + b

for b in xrange(10): 
   xdata = np.zeros((len(x1),2))  # initialize a matrix
   xdata[:,0] = x1  # your original x-data
   xdata[:,1] = b  # your fixed parameter
   popt,pcov = curve_fit(func,xdata,x2)  # x2 is your y-data
yrwegjxp

yrwegjxp3#

可以将func Package 在lambda中,如下所示:

def func(x, a, b):
   return a*x*x + b

for b in xrange(10):
   popt, pcov = curve_fit(lambda x, a: func(x, a, b), x1, x2)

lambda是一个匿名函数,在Python中只能用于简单的单行函数。基本上,当不需要为函数赋值时,它通常用于减少代码量。更详细的描述在官方文档中给出:http://docs.python.org/tutorial/controlflow.html#lambda-forms
在本例中,lambda用于修复func的一个参数,新创建的函数只接受两个参数:xa,而b固定为从本地b变量中获取的值。然后,将此新函数作为参数传递到curve_fit

j8yoct9x

j8yoct9x4#

一个更好的方法是使用lmfit,它为曲线拟合提供了一个更高级别的接口。Lmfit使拟合参数成为一级对象,可以有边界或显式固定(在其他特性中)。
使用lmfit,这个问题可以解决为:

from lmfit import Model
def func(x,a,b):
   return a*x*x + b

# create model
fmodel = Model(func)
# create parameters -- these are named from the function arguments --
# giving initial values
params = fmodel.make_params(a=1, b=0)

# fix b:
params['b'].vary = False

# fit parameters to data with various *static* values of b:
for b in range(10):
   params['b'].value = b
   result = fmodel.fit(ydata, params, x=x)
   print(": b=%f, a=%f+/-%f, chi-square=%f" % (b, result.params['a'].value, 
                                             result.params['a'].stderr,
                                             result.chisqr))
lyr7nygr

lyr7nygr5#

我建议不要使用lambda函数,因为它可能不太直观,而要指定scikit curve_fit参数bounds,它将强制在自定义边界内搜索参数。
您所要做的就是让变量***a***在-inf和+inf之间移动,让变量***b***在(b-epsilon)和(b+ epsilon)之间移动。
在您的示例中:

epsilon = 0.00001

def func(x,a,b):
    return a*x*x + b

for b in xrange(10):
    popt,pcov = curve_fit(func,x1,x2, bounds=((-np.inf,b-epsilon), (np.inf,b+epsilon))
ckx4rj1h

ckx4rj1h6#

我有效地使用了Anton Beloglazov的解决方案,尽管我喜欢避免使用lambda函数来提高可读性,所以我做了以下操作:

def func(x,a,b):
   return a*x*x + b

def helper(x,a):
   return func(x,a,b)

for b in xrange(10):
   popt,pcov = curve_fit(helper, x1, x2)

这最终会让人想起Rick贝格的答案,但我喜欢用一个函数来处理问题的“物理”,用一个帮助函数来使代码工作。

f8rj6qna

f8rj6qna7#

另一种方法是使用与初始值相同(+ eps)的上界和下界。使用相同的初始条件和边界示例:

def func(x,a,b):
   return a*x*x + b
# free for a and b
popt,pcov = curve_fit(func, x1, x2, 
                      p0=[1,1], 
                      bounds=[(-inf,-inf),(inf,inf)])

# free for a; fixed for b  ; 
eps=1/100
popt,pcov = curve_fit(func, x1, x2, 
                      p0=[1,1], 
                      bounds=[(-inf,(1-eps)),(inf,(1+eps))])

记住插入一个epsilon,否则a和b必须相同

相关问题