在python中只使用具有许多参数的函数的一个参数

时间:2012-08-31 03:46:29

标签: python scipy curve-fitting

在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获取循环变量的值。怎么办呢?

7 个答案:

答案 0 :(得分:40)

您可以将func包装在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

答案 1 :(得分:1)

我建议您不要使用可能不太直观的lambda函数来指定scikit curve_fit参数bounds,它会强制在自定义边界内搜索参数。

您所要做的就是让变量 在-inf和+ inf之间移动,而变量 b < / strong>之间( 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))

答案 2 :(得分:0)

如果您愿意/能够编辑原始功能,则有一个更简单的选项。

将您的功能重新定义为:

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

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

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

警告:该函数需要在调用它的同一个脚本中定义。

答案 3 :(得分:0)

Scipy的curve_fit接受三个位置参数,即func,xdata和ydata。 因此,一种替代方法(使用函数包装器)是通过构建一个既包含原始xdata(x1)又包含固定参数b的第二列的矩阵,将b视为xdata(即独立变量)。

假设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

答案 4 :(得分:0)

我有效地使用了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 Berg)的答案,但是我喜欢拥有一个专门用于解决问题的“物理学”的功能,以及一个使代码正常工作的辅助功能。

答案 5 :(得分:0)

另一种方法是使用与初始值相同(+ 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必须相同

答案 6 :(得分:-1)

更好的方法是使用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))