七参数四指数函数数据拟合报错求助:生成NaN值终止拟合
解决四指数函数拟合时的NaN报错问题
问题背景
需要将以下时间-浓度数据拟合到七参数四指数函数:
# 时间数据(单位:min/10) time = np.array([0.075, 0.1, 0.125, 0.15, 0.175, 0.2, 0.25, 0.3, 0.35, 0.4, 0.5, 0.6, 0.8, 1, 1.5, 2, 3, 4.5, 6]) # 浓度数据 concentration = np.array([2.148738, 24.88158, 61.81409, 82.55928, 79.09638, 79.45628, 28.19074, 18.6571, 16.04993, 14.16715, 11.87659, 9.680828, 7.948303, 8.233573, 7.285041, 6.576602, 6.100967, 5.581709, 5.389457])
目标拟合函数:
$$Cp(t) = A_1 e^{-L_1 t} + A_2 e^{-L_2 t} + A_3 e^{-L_3 t} - (A_1+A_2+A_3)e^{-L_4 t}$$
使用curve_fit时出现报错:
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;
- 参数约束不足:仅设置参数下限,未对L值设置上限,过大的L会导致指数计算溢出。
解决步骤与完整代码
1. 重写拟合函数(向量运算替代循环)
用numpy向量运算直接处理整个数组,避免循环中的单个元素错误,提升稳定性与效率:
def Cp(x, A1, L1, A2, L2, A3, L3, L4): term1 = A1 * np.exp(-x * L1) term2 = A2 * np.exp(-x * L2) term3 = A3 * np.exp(-x * L3) term4 = (A1 + A2 + A3) * np.exp(-x * L4) return term1 + term2 + term3 - term4
2. 优化参数初始值与约束
根据数据趋势(快速上升后快速下降,再缓慢衰减)手动设置初始值,并给L参数添加上限,防止指数溢出:
import matplotlib matplotlib.use('TkAgg') import matplotlib.pyplot as plt import numpy as np import lmfit # 重写后的拟合函数 def Cp(x, A1, L1, A2, L2, A3, L3, L4): term1 = A1 * np.exp(-x * L1) term2 = A2 * np.exp(-x * L2) term3 = A3 * np.exp(-x * L3) term4 = (A1 + A2 + A3) * np.exp(-x * L4) return term1 + term2 + term3 - term4 # 加载数据 time = np.array([0.075, 0.1, 0.125, 0.15, 0.175, 0.2, 0.25, 0.3, 0.35, 0.4, 0.5, 0.6, 0.8, 1, 1.5, 2, 3, 4.5, 6]) concentration = np.array([2.148738, 24.88158, 61.81409, 82.55928, 79.09638, 79.45628, 28.19074, 18.6571, 16.04993, 14.16715, 11.87659, 9.680828, 7.948303, 8.233573, 7.285041, 6.576602, 6.100967, 5.581709, 5.389457]) # 创建模型与参数设置 model = lmfit.Model(Cp, independent_vars=['x']) params = model.make_params( A1=80, L1=20, A2=50, L2=10, A3=20, L3=5, L4=0.5 ) # 添加参数约束:所有参数非负,L值上限防止溢出 for param_name in params: params[param_name].min = 0 if param_name.startswith('L'): params[param_name].max = 100 # 执行拟合 fit_result = model.fit(concentration, x=time, params=params) # 输出拟合报告 print(fit_result.fit_report()) # 绘制拟合结果 plt.scatter(time, concentration, label='实验数据') plt.plot(time, fit_result.best_fit, 'r-', label='拟合曲线') plt.xlabel('时间 (min/10)') plt.ylabel('浓度') plt.legend() plt.show()
关键改进说明
- 向量运算:消除循环带来的数值不稳定问题,同时提升计算速度;
- 合理初始值:根据数据趋势设定初始值,帮助拟合算法快速收敛到合理参数范围;
- 参数约束:给L值设置上限,避免指数计算中出现溢出导致NaN;
- lmfit直接拟合:相比
curve_fit,lmfit的参数优化机制更适合多参数复杂模型,自带的参数约束与报告输出更便捷。
内容的提问来源于stack exchange,提问作者Advt 75
相关产品推荐
相关产品推荐

