在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
采用循环变量的值。如何实现?
在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
采用循环变量的值。如何实现?
您可以使用lambda将func
进行封装,如下所示:
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
其中一个参数。新创建的函数仅接受两个参数:x
和a
,而b
被固定为从本地变量b
中获取的值。然后,将这个新函数作为参数传递给curve_fit
函数。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))
建议不要使用 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))
curve_fit(..., absolute_sigma=False)
,则返回的协方差矩阵(即您的pcov
)将为2x2,并且假定有2个变量进行重新缩放,即使只有1个实际变量。因此,a
的不确定性将被错误地估计。如果b
不是一个变量,请不要将它作为一个没有更改其值的自由度的变量。 - M Newville我有效地使用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)
Scipy的curve_fit函数需要三个位置参数:func、xdata和ydata。 因此,除了使用函数包装器的方法外,另一种方法是将'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
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 必须相同。
如果您愿意/能够编辑原始函数,则有一个更简单的选项。
将您的函数重新定义为:
def func(x,a):
return a*x*x + b
然后你可以将它简单地放在你的循环中作为参数 b:
for b in xrange(10):
popt,pcov = curve_fit(func, x1, x2)