LMFIT如何实现仅输出正值的最优拟合?
强制拟合结果始终为正值的实现方法
我希望强制最优拟合结果始终为正值,当前使用lmfit的代码如下:
from lmfit.models import ExpressionModel from lmfit.models import StepModel step_mod = StepModel(form='linear', prefix='step_') gmod = ExpressionModel("1-exp_amp*exp(-x/exp_decay)") mod = gmod*step_mod pars = gmod.make_params(exp_amp=1, exp_decay=30) pars += step_mod.guess(y, x=x, amplitude=1,center=23,sigma=0) out = mod.fit(y, pars, x=x) print(out.fit_report()) plt.plot(x, y,'o') # plt.plot(x, out.init_fit, '--', label='initial fit') plt.plot(x, out.best_fit, '-', label='best fit') plt.legend() plt.show()
当前拟合结果:
[[Model]] (Model(_eval) * Model(step, prefix='step_', form='linear')) [[Fit Statistics]] # fitting method = leastsq # function evals = 37 # data points = 370 # variables = 5 chi-square = 2.53597470 reduced chi-square = 0.00694788 Akaike info crit = -1833.68223 Bayesian info crit = -1814.11472 ## Warning: uncertainties could not be estimated: step_center: at initial value step_sigma: at boundary [[Variables]] exp_amp: 1.80889259 (init = 1) exp_decay: 40.0313587 (init = 30) step_amplitude: 1.02997887 (init = 1) step_center: 23.0000000 (init = 23) step_sigma: 0.00000000 (init = 0)
当前拟合存在两个问题:一是拟合不够理想(比如step_center和step_sigma始终停留在初始值);二是手动调整阶跃函数的center后,拟合结果出现负值。请问如何实现仅输出正值的拟合结果?
解决方案
要实现拟合结果始终为正,同时解决参数拟合停滞的问题,可以从以下几个方面入手:
1. 给参数设置物理约束
lmfit支持通过min和max给参数设置取值范围,确保关键参数为正,同时避免边界值导致拟合停滞:
# 给指数模型参数设置下限,避免出现负值或除以0 pars['exp_amp'].min = 0 pars['exp_decay'].min = 1e-6 # 给阶跃模型参数设置合理范围,sigma避免设为0 pars['step_amplitude'].min = 0 pars['step_sigma'].min = 1e-6 pars['step_center'].min = x.min() pars['step_center'].max = x.max()
2. 修改表达式模型确保输出为正
原表达式1-exp_amp*exp(-x/exp_decay)可能在某些x取值下出现负值,可通过max函数强制结果非负:
gmod = ExpressionModel("max(0, 1-exp_amp*exp(-x/exp_decay))")
3. 调整初始参数与拟合方法
- 不要将
step_sigma初始值设为0,给一个小的正值(比如sigma=1),让拟合器有调整空间; - 若leastsq方法陷入局部最优,可尝试使用鲁棒性更强的拟合方法,比如
nelder或differential_evolution:
out = mod.fit(y, pars, x=x, method='nelder')
4. 合并模型逻辑(可选)
如果阶跃函数的作用是控制指数项的生效区间,可将逻辑整合到表达式模型中,减少参数数量,提升拟合稳定性:
# 整合阶跃与指数模型,直接用条件判断控制激活区间 gmod = ExpressionModel("max(0, (1-exp_amp*exp(-x/exp_decay)) * (x >= step_center))") pars = gmod.make_params(exp_amp=1, exp_decay=30, step_center=23) pars['step_center'].min = x.min() pars['step_center'].max = x.max()
内容的提问来源于stack exchange,提问作者Keflux
相关产品推荐
相关产品推荐

