在python中使用scipy的curvefit拟合Boxcar函数的问题


问题内容

我无法使这种棚车适合工作……我得到了 “ OptimizeWarning:无法估计参数的协方差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中,指定一个蒙特卡洛优化将是微不足道的。


问题答案:

我怀疑此函数形式不适合Curve_fit使用的levenberg-marquardt算法

你是对的。通常,基于梯度的优化不适用于具有尖锐边缘的函数。通过稍微干扰功能参数并查看装配质量的变化来估算梯度。但是,如果边缘不与数据点交叉,则稍微移动边缘将导致零梯度:

在此处输入图片说明

  • 答:很容易拟合振幅,因为高度的微小变化会立即导致残差的变化。
  • 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()

在此处输入图片说明