使用lmfit拟合自定义对数模型时触发NaN值错误排查
自定义对数函数拟合触发NaN错误排查
数据
y=[2.103402,2.426855,1.011672,1.595371,1.861879,2.492542,2.567561,4.685010,4.452643,5.321630,6.637233, 6.109260,6.220958,5.928408,5.654726,5.498096,5.468448,6.128418,6.071376,6.487270,6.609533,6.907320, 7.626838,8.432065,9.749410,8.976752,8.742036,8.779956,8.212357,8.578200,9.170012,9.134267,9.199465, 9.094945,9.342948,9.802524,10.959913,10.488497,10.892593,10.673570,10.608582,10.036824,9.741473] x=[300,400,500,600,700,800,900,1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2100,2200,2300, 2400,2500,2600,2700,2800,2900,3000,3100,3200,3300,3400,3500,3600,3700,3800,3900,4000,4100,4200,4300,4400,4500]
数据形态:整体呈现先上升后趋于平稳的趋势。
自定义拟合函数
def log_n_func(x, a, b, c, n): return a*(np.log(b+x)/np.log(n))+c
尝试的两种实现方式
方式一
import lmfit def log_n_func(x, a, b, c, n): return a*(np.log(b+x)/np.log(n))+c regressor = lmfit.Model(log_n_func) initial_guess = dict(a=3.61, b=443.86, c=-34, n=2) results = regressor.fit(data=y, x=x, **initial_guess) y_fit = results.best_fit
方式二
from lmfit import Model, Parameters model = Model(log_n_func, independent_vars=['x'], param_names=["a", "b", "c", "n"]) params = Parameters() params.add("a", value=3.6) params.add("b", value=440) params.add("c", value=-34) params.add("n", value=2) result = model.fit(data=y, params=params, x=x)
触发的错误
ValueError: The model function generated NaN values and the fit aborted! Please check your model function and/or set boundaries on parameters where applicable. In cases like this, using "nan_policy='omit'" will probably not work.
问题
请问我哪里操作出错了?
解决方案
NaN错误的根源是拟合过程中参数被优化到了非法取值范围,导致对数函数或除法运算失效:
- 参数n的问题:当n被调整到≤1时,
np.log(n)会变成0(n=1时)或负数(n<1时),除以0直接产生NaN;结合数据趋势,n作为对数底数应该大于1,因此需要限制n的最小值。 - 参数b的问题:x的最小值是300,如果b被调整到≤-300,会导致
b+x≤0,而np.log的输入不能是非正数,直接产生NaN,因此需要限制b的最小值。
修改后的代码示例
方式一优化版
import lmfit import numpy as np def log_n_func(x, a, b, c, n): return a*(np.log(b+x)/np.log(n))+c regressor = lmfit.Model(log_n_func) # 生成参数对象并设置边界 params = regressor.make_params(a=3.61, b=443.86, c=-34, n=2) params['n'].min = 1.0001 # 确保n>1,避免log(n)为0或负数 params['b'].min = -299 # 确保b+x>0(x最小为300) results = regressor.fit(data=y, x=x, params=params) y_fit = results.best_fit # 查看拟合结果报告 print(results.fit_report())
方式二优化版
from lmfit import Model, Parameters import numpy as np def log_n_func(x, a, b, c, n): return a*(np.log(b+x)/np.log(n))+c model = Model(log_n_func, independent_vars=['x'], param_names=["a", "b", "c", "n"]) params = Parameters() params.add("a", value=3.6) params.add("b", value=440, min=-299) # 限制b的最小值 params.add("c", value=-34) params.add("n", value=2, min=1.0001) # 限制n的最小值 result = model.fit(data=y, params=params, x=x) # 查看拟合结果报告 print(result.fit_report())
通过给参数设置合理的取值边界,就能避免拟合过程中产生NaN,顺利完成拟合。
内容的提问来源于stack exchange,提问作者smaica
相关产品推荐
相关产品推荐

