我怀疑这种函数形式不适合 curve_fit 使用的 levenberg-marquardt 算法
你是对的。一般来说,基于梯度的优化不太适合具有锐利边缘的函数。通过稍微扰动函数参数并查看拟合质量的变化来估计梯度。然而,如果边缘不穿过数据点,稍微移动边缘就会导致梯度为零:
- 答:拟合振幅很容易,因为高度的微小变化会立即导致残差的变化。
- B:很难拟合边缘,因为位置的微小变化不会影响残差(除非变化大到足以使边缘穿过数据点)。
使用随机方法应该效果更好。 Scipy 有微分进化函数,它使用遗传算法,因此与蒙特卡罗方法相关。然而,它的使用并不比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()