在curve_fit中修复拟合参数

时间:2017-12-19 10:29:26

标签: python scipy curve-fitting

我有一个函数Imaginary,它描述了一个物理过程,我希望将其与数据集x_interpolate, y_interpolate相匹配。该函数是洛伦兹峰函数的一种形式,我有一些用户给出的初始值,除了我使用峰值查找算法找到的f_peak(峰值位置)。除偏移之外的所有拟合参数都应该是正的,因此我相应地设置了bounds_I

def Imaginary(freq, alpha, res, Ms, off):
    numerator = (2*alpha*freq*res**2)
    denominator = (4*(alpha*res*freq)**2) + (res**2 - freq**2)**2
    Im = Ms*(numerator/denominator) + off
    return Im

pI = np.array([alpha_init, f_peak, Ms_init, 0])

bounds_I = ([0,0,0,0, -np.inf], [np.inf,np.inf,np.inf, np.inf])

poptI, pcovI = curve_fit(Imaginary, x_interpolate, y_interpolate, pI, bounds=bounds_I)

在某些情况下,我希望在拟合过程中保持参数f_peak不变。我通过将bounds_I更改为:

来尝试一种简单的解决方案
bounds_I = ([0,f_peak+0.001,0,0, -np.inf], [np.inf,f_peak-0.001,np.inf, np.inf])

这有很多原因并非最佳方式,所以我想知道是否有更多的Pythonic方法吗?谢谢你的帮助

2 个答案:

答案 0 :(得分:3)

如果参数是固定的,它实际上不是一个参数,因此应该从参数列表中删除它。定义一个模型,该模型将该参数替换为固定值,并使其适合。以下示例,简化为简洁和自包含:

x = np.arange(10)
y = np.sqrt(x)    
def parabola(x, a, b, c):
  return a*x**2 + b*x + c

fit1 = curve_fit(parabola, x, y)  #  [-0.02989396,  0.56204598,  0.25337086]
b_fixed = 0.5
fit2 = curve_fit(lambda x, a, c: parabola(x, a, b_fixed, c), x, y) 

第二次调用fit返回[-0.02350478, 0.35048631],这是a和c的最佳值。 b的值固定为0.5。

当然,该参数也应该从初始向量pI和边界中删除。

答案 1 :(得分:0)

您可能会发现lmfit(https://lmfit.github.io/lmfit-py/)很有帮助。该库为scipy优化例程添加了更高级别的接口,旨在实现更优化和曲线拟合的Pythonic方法。例如,它使用Parameter对象来允许设置边界和修复参数,而无需修改目标或模型函数。对于曲线拟合,它定义了可以使用的高级模型函数。

对于您的示例,您可以使用Imaginary函数,因为您已经用

编写了它
from lmfit import Model
lmodel = Model(Imaginary)

然后创建参数(lmfit将根据您的函数签名命名Parameter对象),提供初始值:

params = lmodel.make_params(alpha=alpha_init, res=f_peak, Ms=Ms_init, off=0)

默认情况下,所有参数都是未绑定的,并且在拟合方面会有所不同,但您可以修改这些属性(不重写模型函数):

params['alpha'].min = 0
params['res'].min = 0
params['Ms'].min = 0

您可以设置一个(或多个)参数在拟合中不变,如:

params['res'].vary = False

要明确:这不需要改变模型函数,使得更改更容易修复,可能施加的界限等等。

然后,您将使用模型和这些参数进行拟合:

result = lmodel.fit(y_interpolate, params, freq=x_interpolate)

您可以使用

获取有关参数的拟合统计数据,最佳拟合值和不确定性的报告
print(result.fit_report())

最佳拟合参数将保存在result.params

FWIW,lmfit还有许多常见形式的内置模型,包括Lorentzian和Constant偏移。因此,您可以将此模型构建为

from lmfit.models import LorentzianModel, ConstantModel

mymodel = LorentzianModel(prefix='l_') + ConstantModel()

params = mymodel.make_params()

将包含名为l_amplitudel_centerl_sigmac的参数(其中c为常量),模型将使用名称x表示自变量(freq)。当您可能想要更改峰或背景的功能形式,或将多个峰拟合到光谱时,此方法可以变得非常方便。