SciPy全局最小值曲线拟合

8 投票
3 回答
5111 浏览
提问于 2025-04-16 14:10

我正在使用 scipy.optimize.curve_fit 这个工具,但我怀疑它找到的只是一个局部最小值,而不是全局最小值。

我尝试用模拟退火的方法,代码如下:

def fit(params):
 return np.sum((ydata - specf(xdata,*params))**2)

p = scipy.optimize.anneal(fit,[1000,1E-10])

这里的 specf 是我想要拟合的曲线。不过,结果中的 p 明显比 curve_fit 返回的最小值要差,即使返回值显示已经达到了全局最小值(查看模拟退火)。

我该如何改善结果呢?在 SciPy 中有没有全局曲线拟合的工具?

3 个回答

1

这个问题并不简单。你有没有考虑过使用进化策略呢?我用ecspy这个工具取得了很好的效果(可以查看这里:http://code.google.com/p/ecspy/),虽然这个社区不大,但非常乐于助人。

3

你可以试试使用 leastsq() 这个函数(其实 curve_fit 也是用这个的,但你得不到完整的输出)。或者你也可以使用 ODR 包,而不是 curve_fit。

leastsq() 的完整输出会给你更多的信息,比如卡方值(如果你想用它来快速判断拟合的好坏)。

如果你需要给拟合加权,可以这样做:

fitfunc = lambda p,x: p[0]+ p[1]*exp(-x)
errfunc = lambda p, x, y, xerr: (y-fitfunc(p,x))/xerr
out = leastsq(errfunc, pinit, args=(x,y, xerr), full_output=1)
chisq=sum(infodict['fvec']*infodict['fvec'])
7

你说得对,它只会朝着一个局部最小值收敛(如果它能收敛的话),因为它使用的是Levenburg-Marquardt算法。在SciPy里没有全局曲线拟合的工具,你需要自己写一个,利用现有的全局优化器。不过要注意,这样做也不一定能得到你想要的结果。在大多数情况下,这种情况是不可能的。

改善结果的唯一方法就是要很好地猜测起始参数。

撰写回答