如何将数据点拟合到y=ae^(px+qx²)模型?curve_fit拟合失败求助
问题原因
- 模型参数尺度差异极大:a的数量级在1e-140左右,p、q的数量级为100~101,
curve_fit默认的Levenberg-Marquardt优化算法对参数尺度差异非常敏感,即便初值接近也很容易陷入数值不稳定的情况,导致拟合失败。 - 指数项计算会出现极大/极小值,进一步加剧浮点数精度问题,导致优化器迭代步长异常。
解决方案
方案1:对数变换转线性拟合(最稳妥,不需要初值)
你的模型本身属于对数线性模型,直接对两边取自然对数即可转换为二次多项式线性回归问题,完全规避非线性拟合的数值问题:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit k = 0.00008617 def NormalizeData(data): # 归一化时加微小偏移避免y为0,防止取对数报错 norm = (data - np.min(data)) / (np.max(data) - np.min(data)) return norm + 1e-10 def C_to_A(C): return -1/(k*(C+273)) def model(x, a, p,q): return a*np.exp(p*x+q*x**2) # 输入数据 x = C_to_A(np.array([11, 11, 11,15,15,15,20,20,20,25,25,25,29,29,29])) y = NormalizeData(np.array([2.048, 1.56, 1.18, 2.6116,2.35,2.1036,2.97, 2.97, 2.97, 2.463,2.05,1.6679,1.825,1.0939,0.534])) # 对数变换后做二次线性拟合 log_y = np.log(y) # 构造X矩阵:[常数项, x, x²] X = np.vstack([np.ones_like(x), x, x**2]).T # 最小二乘求解 coeffs, _, _, _ = np.linalg.lstsq(X, log_y, rcond=None) a_fit = np.exp(coeffs[0]) p_fit = coeffs[1] q_fit = coeffs[2] print(f"拟合得到的参数:a={a_fit}, p={p_fit}, q={q_fit}") # 绘图 xx = np.linspace(-50, -35) yy = model(xx, a_fit, p_fit, q_fit) plt.plot(x, y, 'o', label='原始数据') plt.plot(xx, yy, label='拟合曲线') plt.title('Exponential Fit') plt.ylim(0,1.1) plt.xlim(-50,-35) plt.grid() plt.legend() plt.show()
方案2:调整curve_fit参数继续使用非线性拟合
如果必须使用curve_fit,可以增加边界约束、更换更适配的优化器:
# 初始值沿用你手动测试的结果 p0 = (9.7e-140, -16, -0.2) # 增加参数边界约束,使用trf优化器 popt, pcov = curve_fit(model, x, y, p0=p0, bounds=([1e-145, -20, -1], [1e-135, -10, 0]), method='trf') print(f"curve_fit拟合得到的参数:a={popt[0]}, p={popt[1]}, q={popt[2]}")
注意事项
你原来的代码中x的实际取值范围在-49到-38左右,绘图的xlim设置成(-50,32)是错误的,32远大于x的实际范围,会导致拟合曲线在无数据区域显示异常,建议调整为xlim(-50,-35)即可。
内容的提问来源于stack exchange,提问作者Rami2314
相关产品推荐
相关产品推荐

