关于lmfit的绝对值边界设置问题:拟合存在未定义区间的函数
关于lmfit的绝对值边界设置问题:拟合存在未定义区间的函数
兄弟,我太懂你这种拟合时碰到参数跨零踩坑的糟心了!你说的这个双向指数高斯函数,估计在gamma=0的时候是个奇点或者函数形式直接发生了突变,所以拟合算法在gamma接近0的时候很容易卡壳、发散或者出异常结果对吧?
我给你分享几个实用的解决思路,都是我自己踩过坑后摸索出来的:
用“绝对值+符号参数”绕开零点
这是最稳妥的方法,直接把gamma拆成两个参数,彻底避开gamma=0的区间:- 新增
gamma_abs参数,设置它的下限为一个极小的正数(比如1e-6),确保它永远不会接近0; - 再新增
gamma_sign参数,让它只负责控制正负,你可以把它的范围设为[-1, 1],或者直接强制它取+1/-1; - 最后在拟合函数里,把实际用的
gamma定义为gamma_sign * gamma_abs。
给你段示例代码参考:
from lmfit import Model, Parameters import numpy as np def bidirectional_exp_gauss(x, center, amplitude, sigma, gamma_abs, gamma_sign): # 组合出实际的gamma参数 gamma = gamma_sign * gamma_abs # 这里替换成你实际的双向指数高斯函数实现 exp_term = np.exp(-((x - center)/sigma)**2 / 2) gamma_term = np.exp(gamma * (x - center)/sigma) return amplitude * exp_term * gamma_term # 初始化模型和参数 model = Model(bidirectional_exp_gauss) params = Parameters() params.add('center', value=10, min=0) params.add('amplitude', value=5, min=0) params.add('sigma', value=2, min=1e-6) params.add('gamma_abs', value=0.3, min=1e-6) # gamma_sign控制正负,范围设为-1到1即可 params.add('gamma_sign', value=1, min=-1, max=1, vary=True) # 执行拟合 result = model.fit(your_y_data, params, x=your_x_data) print(result.fit_report())- 新增
分两次拟合后选最优结果
如果你觉得拆参数麻烦,也可以直接分两次拟合:一次把gamma限制为正数(下限设为1e-6),一次限制为负数(上限设为-1e-6),最后比较两次拟合的残差,选残差更小的那个结果。这种方法简单粗暴,但胜在直观,完全不会碰到零点的问题。示例代码如下:
from lmfit import Model, Parameters import numpy as np # 先定义原始的拟合函数 def bidirectional_exp_gauss(x, center, amplitude, sigma, gamma): exp_term = np.exp(-((x - center)/sigma)**2 / 2) gamma_term = np.exp(gamma * (x - center)/sigma) return amplitude * exp_term * gamma_term model = Model(bidirectional_exp_gauss) # 第一次拟合:gamma为正 params_pos = Parameters() params_pos.add('center', value=10, min=0) params_pos.add('amplitude', value=5, min=0) params_pos.add('sigma', value=2, min=1e-6) params_pos.add('gamma', value=0.3, min=1e-6) result_pos = model.fit(your_y_data, params_pos, x=your_x_data) # 第二次拟合:gamma为负 params_neg = Parameters() params_neg.add('center', value=10, min=0) params_neg.add('amplitude', value=5, min=0) params_neg.add('sigma', value=2, min=1e-6) params_neg.add('gamma', value=-0.3, max=-1e-6) result_neg = model.fit(your_y_data, params_neg, x=your_x_data) # 选残差小的作为最优结果 best_result = result_pos if result_pos.chisqr < result_neg.chisqr else result_neg print(best_result.fit_report())
最后再提个小建议:不管用哪种方法,初始参数的设置都很关键!如果初始值离真实值太远,拟合很容易跑偏,最好先根据你的数据大致判断下gamma的正负,给个靠谱的初始值,拟合成功率会高很多。
备注:内容来源于stack exchange,提问作者Joshua Derrick
相关产品推荐
相关产品推荐

