Scipy curve_fit拟合效果差,Python有哪些更稳定的曲线拟合库?
问题原因
你遇到的报错和拟合效果差的问题是操作疏漏导致的,和scipy curve_fit本身的稳定性无关。
curve_fit默认使用非线性最小二乘算法做拟合,这类算法对参数初始值非常敏感,如果你不指定初始值,curve_fit会默认给所有参数赋值为1作为迭代起点:
- 你真实参数a=823.5,和默认初始值1差距过大
- 你真实参数c=8.2,对应$e^{-8.2x}$在x>0.5之后就已经衰减到接近0,算法用初始值1迭代时,很难捕捉到这么快的衰减特征,很容易陷入梯度为0的局部最优,导致参数无法收敛,自然无法估算协方差,抛出你看到的警告。
修复方法
只需要在调用curve_fit时传入和真实参数接近的初始值列表p0即可,修改后的代码如下:
import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit def func(x, a, b, c): return a - b*np.exp(-c*x) xdata = np.linspace(0, 4, 50) y = func(xdata, 823.5, 5.3, 8.2) rng = np.random.default_rng() y_noise = 0.2 * rng.normal(size=xdata.size) ydata = y + y_noise plt.plot(xdata, ydata, 'b-', label='data') # 新增p0参数指定初始值 popt, pcov = curve_fit(func, xdata, ydata, p0=[800, 5, 8]) plt.plot(xdata, func(xdata, *popt), 'r-', label='fit: a=%5.3f, b=%5.3f, c=%5.3f' % tuple(popt)) plt.plot(xdata, y, 'g--', label='Original') plt.xlabel('x') plt.ylabel('y') plt.legend() plt.show()
修改后运行不会再抛出警告,拟合参数和原始参数误差会控制在0.2的噪声范围内,拟合效果完全正常。如果不清楚参数的大致范围,也可以给curve_fit传入bounds参数限定参数的上下界,同样可以大幅提升收敛概率。
更稳定的Python曲线拟合库推荐
lmfit:基于scipy的优化接口封装,专门面向曲线拟合场景,支持给参数设置默认值、边界、固定参数值、参数别名等功能,接口比原生curve_fit更友好,收敛性表现更好,是目前最常用的Python非线性拟合库之一。symfit:符号化拟合工具,基于sympy和scipy开发,不需要手动写残差函数,直接通过符号表达式定义拟合函数即可,语法对新手更友好,内置了多种收敛优化策略。- 对于指数、幂律这类可以做变量转换的函数,也可以先通过
numpy.polynomial做线性拟合估算初始参数,再代入非线性拟合,稳定性远高于直接调用默认参数的非线性拟合。
内容的提问来源于stack exchange,提问作者Jonny Joker
相关产品推荐
相关产品推荐

