修复 curve_fit 中的拟合参数
Fixing fit parameters in curve_fit
我有一个描述物理过程的函数 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 的方式来执行此操作?感谢您的帮助
如果一个参数是固定的,它就不是真正的参数,所以应该从参数列表中删除。定义一个模型,该模型将该参数替换为固定值,并对其进行拟合。下面的示例,为简洁起见进行了简化并且是独立的:
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)
第二次调用拟合returns[-0.02350478, 0.35048631]
,即a和c的最优值。 b 的值固定为 0.5。
当然,参数应该从初始向量pI和边界中移除。
您可能会发现 lmfit (https://lmfit.github.io/lmfit-py/) 很有帮助。该库为 scipy 优化例程添加了一个更高级别的接口,旨在采用更 Pythonic 的优化和曲线拟合方法。例如,它使用 Parameter 对象来设置边界和固定参数,而无需修改 objective 或模型函数。对于曲线拟合,它定义了可以使用的高级模型函数。
例如,您可以使用 Imaginary
函数,就像您用
编写的那样
from lmfit import Model
lmodel = Model(Imaginary)
然后创建Parameters(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 还具有许多常见形式的内置模型,包括洛伦兹和常量偏移。因此,您可以将此模型构建为
from lmfit.models import LorentzianModel, ConstantModel
mymodel = LorentzianModel(prefix='l_') + ConstantModel()
params = mymodel.make_params()
将具有名为 l_amplitude
、l_center
、l_sigma
和 c
的参数(其中 c
是常量)并且模型将使用自变量的名称 x
(您的 freq
)。当您可能想要更改峰或背景的函数形式,或者将多个峰拟合到光谱时,这种方法会变得非常方便。
我有一个描述物理过程的函数 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 的方式来执行此操作?感谢您的帮助
如果一个参数是固定的,它就不是真正的参数,所以应该从参数列表中删除。定义一个模型,该模型将该参数替换为固定值,并对其进行拟合。下面的示例,为简洁起见进行了简化并且是独立的:
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)
第二次调用拟合returns[-0.02350478, 0.35048631]
,即a和c的最优值。 b 的值固定为 0.5。
当然,参数应该从初始向量pI和边界中移除。
您可能会发现 lmfit (https://lmfit.github.io/lmfit-py/) 很有帮助。该库为 scipy 优化例程添加了一个更高级别的接口,旨在采用更 Pythonic 的优化和曲线拟合方法。例如,它使用 Parameter 对象来设置边界和固定参数,而无需修改 objective 或模型函数。对于曲线拟合,它定义了可以使用的高级模型函数。
例如,您可以使用 Imaginary
函数,就像您用
from lmfit import Model
lmodel = Model(Imaginary)
然后创建Parameters(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 还具有许多常见形式的内置模型,包括洛伦兹和常量偏移。因此,您可以将此模型构建为
from lmfit.models import LorentzianModel, ConstantModel
mymodel = LorentzianModel(prefix='l_') + ConstantModel()
params = mymodel.make_params()
将具有名为 l_amplitude
、l_center
、l_sigma
和 c
的参数(其中 c
是常量)并且模型将使用自变量的名称 x
(您的 freq
)。当您可能想要更改峰或背景的函数形式,或者将多个峰拟合到光谱时,这种方法会变得非常方便。