含4个参数的复杂函数曲线拟合遇RuntimeError问题求助
解决scipy.curve_fit拟合复杂函数时的maxfev超限问题
问题概述
使用scipy.optimize.curve_fit拟合自定义复杂函数时,出现以下错误:
RuntimeError: Optimal parameters not found: Number of calls to function has reached maxfev = 10000.
即使增大maxfev到10000000或移除对数项,问题依然存在。原代码中的拟合函数包含多个指数项与对数运算,目标是拟合参数a、b、c、d。
核心原因分析
- 数值合理性错误:原函数中
1 - np.exp(2*38.94336875*x)项会导致分子为负数——当x在1.861.96区间时,`2*38.94*x`约为144152,np.exp(144)是约1e62的极大值,1 - exp(...)近似为-1e62,最终对数内的表达式为负数,计算时会产生NaN,直接导致拟合算法失效。 - 初始参数不合理:
curve_fit默认初始参数全为1,但该复杂函数的参数空间非凸,默认初始值可能离最优解极远,导致迭代无法收敛。 - 重复计算与数值溢出:原函数中大量重复计算指数项,不仅降低效率,还容易引发数值溢出/下溢问题,干扰拟合过程。
解决方案
1. 修正函数的符号错误
根据实验数据y为负数的特征,对数内的表达式必须是0~1之间的正数。因此需修正分子中的符号,将1 - exp(2kx)改为exp(2kx) - 1(或根据物理模型调整为1 - exp(-2kx),确保分子为正),保证对数运算的有效性。
2. 简化函数表达式,优化数值稳定性
预计算常数项、提取重复的指数项,减少计算量与数值误差:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit x = np.array([1.8652, 1.8966, 1.9125, 1.9230, 1.9313, 1.9359, 1.9435, 1.9523, 1.9585, 1.9649]) y = np.array([-0.0597, -0.0596, -0.0607, -0.0617, -0.0628, -0.0637, -0.0646, -0.0658, -0.0668, -0.0677]) # 可视化原始数据 plt.scatter(x, y, c='k') plt.xlabel('x') plt.ylabel('y') plt.grid(True) plt.show() # 修正并简化拟合函数 def f(x, a, b, c, d): k = 38.94336875 # 预计算常数项,减少重复计算 C = 2 * 96485 / 0.000035 # 提取重复的指数项 exp_half_kx_neg = np.exp(-0.5 * k * x) exp_2kx = np.exp(2 * k * x) exp_kx = np.exp(k * x) # 修正符号,确保分子为正 numerator = a * b * exp_half_kx_neg * (exp_2kx - 1) denominator = (a + b) + (c + d) * exp_kx inner = numerator / denominator return np.log10(C * inner)
3. 提供合理的初始参数猜测
根据物理意义或数据趋势,给出接近最优解的初始参数(例如假设参数非负且在0.1~10范围内),避免算法从离群点开始迭代:
# 初始参数猜测,可根据实际模型调整 p0 = [0.1, 0.1, 0.1, 0.1] # 设置参数边界,限制参数范围(这里假设参数非负) args, pcov = curve_fit(f, x, y, p0=p0, maxfev=100000, bounds=(0, [10, 10, 10, 10])) print('拟合参数(a, b, c, d):', args)
4. 验证拟合结果
计算拟合曲线并绘图对比:
y_fit = f(x, *args) plt.scatter(x, y, c='b', label="实验数据") plt.plot(x, y_fit, 'r-', label="拟合曲线") plt.xlabel('x') plt.ylabel('y') plt.legend(loc='best') plt.grid(True) plt.show()
额外优化建议
- 如果参数之间存在相关性,可尝试减少参数数量(例如假设a=c、b=d,根据物理模型简化)。
- 对参数或变量进行缩放,例如将x减去均值,或对参数取对数,优化参数空间的平滑性。
- 若仍不收敛,可尝试使用
scipy.optimize.least_squares替代curve_fit,它支持更多优化算法与约束条件。
内容的提问来源于stack exchange,提问作者Walrus
相关产品推荐
相关产品推荐

