Scipy optimize curve_fit异常:拟合结果异常且报协方差无法估计警告
Scipy曲线拟合异常问题排查
问题重现
运行提供的代码后出现两个异常:
- 拟合曲线仅为第一条数据点附近的微小水平线
- 抛出
OptimizeWarning: Covariance of the parameters could not be estimated警告
原代码(补全缺失的numpy导入):
import numpy as np from scipy import optimize import matplotlib.pyplot as plt x_data = np.linspace(0,11,12) y_data = np.array([0.02471114, 0.02057292, 0.01752668, 0.01494543, 0.01273249, 0.0110999 , 0.00946524, 0.00805622, 0.00670716, 0.00558925, 0.00465331, 0.00387775]) def func(x,a,b): return ((a-1)*(-b*x - (0.024711**(1-a)/(1-a))))**(1/(1-a)) popt,pcov = optimize.curve_fit(func, x_data, y_data, p0=[1.1,0.1]) a_opt, b_opt = popt x_model = np.linspace(min(x_data), max(y_data), 100) y_model = func(x_model, a_opt, b_opt) plt.scatter(x_data, y_data) plt.plot(x_model, y_model, color='r') plt.show()
问题根源分析
1. x_model的范围完全错误
代码中x_model = np.linspace(min(x_data), max(y_data), 100)错误地将x的范围设为[0, 0.0247],而原始x_data的范围是[0,11],导致拟合曲线仅在x趋近于0的极小区间绘制,视觉上呈现为水平线。
2. 拟合函数存在数值不稳定性
原函数形式过于复杂,且硬编码了第一个y值0.024711,当参数a接近1时,1-a为极小值,会引发:
- 幂运算
0.024711**(1-a)的精度丢失或数值溢出 - 分母为极小值导致的计算爆炸,使得拟合算法无法找到有效参数优化方向
3. 初始参数加剧数值问题
初始参数p0=[1.1,0.1]中a非常接近1,进一步放大了数值稳定性问题,导致curve_fit无法收敛,无法估计参数协方差,最终抛出警告。
修复方案
步骤1:修正x_model的范围
将x_model的范围改为与原始x_data一致:
x_model = np.linspace(min(x_data), max(x_data), 100)
步骤2:更换更适配数据的拟合模型
原函数形式复杂且依赖硬编码值,建议使用更贴合数据单调递减趋势的指数衰减模型:
def func(x, c, b): return c * np.exp(-b * x)
步骤3:设置合理初始参数
针对新模型设置符合数据特征的初始参数,避免数值不稳定:
popt, pcov = optimize.curve_fit(func, x_data, y_data, p0=[0.025, 0.1])
完整修复代码
import numpy as np from scipy import optimize import matplotlib.pyplot as plt x_data = np.linspace(0,11,12) y_data = np.array([0.02471114, 0.02057292, 0.01752668, 0.01494543, 0.01273249, 0.0110999 , 0.00946524, 0.00805622, 0.00670716, 0.00558925, 0.00465331, 0.00387775]) # 使用指数衰减模型,适配数据递减趋势 def func(x, c, b): return c * np.exp(-b * x) # 设定合理初始参数 popt, pcov = optimize.curve_fit(func, x_data, y_data, p0=[0.025, 0.1]) c_opt, b_opt = popt x_model = np.linspace(min(x_data), max(x_data), 100) y_model = func(x_model, c_opt, b_opt) plt.scatter(x_data, y_data, label='原始数据') plt.plot(x_model, y_model, color='r', label=f'拟合曲线: y={c_opt:.4f}*exp(-{b_opt:.4f}x)') plt.legend() plt.show()
运行这段代码后,拟合曲线会完美贴合数据,且不会出现协方差估计警告。
内容的提问来源于stack exchange,提问作者willard
相关产品推荐
相关产品推荐

