使用Python中的scipy库的curvefit函数拟合boxcar函数时出现了问题。

3
我无法使这个箱车适应工作... 我收到了"OptimizeWarning: Covariance of the parameters could not be estimated category=OptimizeWarning)",并且输出的系数没有超出起始猜测值的改进。
import numpy as np
from scipy.optimize import curve_fit
def box(x, *p):
    height, center, width = p
    return height*(center-width/2 < x)*(x < center+width/2)

x = np.linspace(-5,5)
y = (-2.5<x)*(x<2.5) + np.random.random(len(x))*.1

coeff, var_matrix = curve_fit(box, x, y, p0=[1,0,2])

输出系数为[1.04499699,0.,2.],请注意第三个系数甚至没有改变。

我怀疑这种函数形式对curve_fit使用的levenberg-marquardt算法不利,这有点让人烦恼,因为我喜欢这个函数。在Mathematica中,指定蒙特卡罗优化将是微不足道的。


1
“工作”是什么意思?那只是一个警告,而不是错误,并告诉您有关估计值信心的信息。但是当我运行您提供的代码片段时,我得到了与数据的合理拟合。 - bnaecker
我在上面添加了一些更多的细节。基本上,系数与起始猜测相比没有任何改进。 - ARN
您发布的代码似乎缺少一些导入语句,无法运行。 - James Phillips
1个回答

5

我怀疑这个函数形式不适合curve_fit使用的Levenberg-Marquardt算法。

你是正确的。通常,基于梯度的优化方法不适用于具有尖锐边缘的函数。梯度是通过稍微扰动函数参数并观察拟合质量的变化来估计的。然而,如果边缘没有穿过数据点,那么将其移动一点就会导致梯度为零:

enter image description here

  • A: 径向振动幅度易于拟合,因为高度的微小变化立即导致残差的变化。
  • B: 边缘很难拟合,因为位置的微小变化不会影响残差(除非变化足够大以使边缘穿过数据点)。

使用随机方法应该效果更好。Scipy有differential_evolution函数,它使用遗传算法,因此与蒙特卡罗方法相关。然而,它比curve_fit更难使用。您需要指定成本函数和参数范围:

res = differential_evolution(lambda p: np.sum((box(x, *p) - y)**2),  # quadratic cost function
                             [[0, 2], [-5, 5], [0.1, 10]])  # parameter bounds

这仍然是一个一行代码 :)

coeff, var_matrix = curve_fit(box, x, y, p0=[1,0,2])

res = differential_evolution(lambda p: np.sum((box(x, *p) - y)**2), [[0, 2], [-5, 5], [0.1, 10]])

plt.step(x, box(x, *coeff), where='mid', label='curve_fit')
plt.step(x, box(x, *res.x), where='mid', label='diff-ev')
plt.plot(x, y, '.')
plt.legend()

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接