使用SciPy的least_squares()进行曲线拟合

时间:2018-03-17 16:16:13

标签: python scipy curve-fitting

我正在用Python进行最小的方形曲线拟合并得到不错的结果,但希望它更健壮。

我有来自一阶LTI系统的数据,更具体地说是由测速计读取的电机的速度。我正在尝试适应电机的阶跃响应,因此我可以推断出它的传递函数。

速度(v(t))具有以下形式: v(t)= K *(1 - exp(-t / T))

我在使用的数据中有一些异常值,并希望减轻它们。这主要发生在速度恒定时。假设速度是10000单位,我有时得到10000 +/- 400的异常值。我想知道如何设置我的f_scale参数给定我希望我的数据点保持在“实际”速度(平均值)的+/- 400之内。我应该将f_scale设置为400还是800?我不确定我应该在那里设置什么。

由于

编辑:一些数据。 enter image description here

1 个答案:

答案 0 :(得分:2)

我构建了一个最小的例子,用于与你的曲线相似的曲线。如果您发布了实际数据而不是图片,那么这会更快一些。关于使用least_squares进行稳健拟合的两个关键要点是,您必须为loss参数使用不同于线性的值,并将f_scale用作损失的缩放参数功能。

基本上,从文档中least_squares尝试

minimize F(x) = 0.5 * sum(rho(f_i(x)**2)

并在上述公式中设置损失loss参数更改rholoss='linear' rho只是身份功能。在loss='soft_l1'rho(z) = 2 * ((1 + z)**0.5 - 1)时。 f_scale用于缩放损失函数,使rho_(f**2) = C**2 * rho(f**2 / C**2)。所以它与你上面提到的含义不同,它更像是一种惩罚较大错误的方法。

在这种特殊情况下,它似乎并没有太大的区别。

import numpy
import matplotlib.pyplot as plt
import scipy.optimize

tmax = 6000
N = 100
K = 6000
T = 200

smootht = numpy.linspace(0, tmax, 1000)
tm = numpy.linspace(0, tmax, N)

def f(t, K, T):
    return K * (1 - numpy.exp(-t/T))

v = f(smootht, K, T)

vm = f(tm, K, T) + numpy.random.randn(N)*400

def error(pars):
    K, T = pars
    vp = f(tm, K, T)
    return vm - vp

f_scales = [0.01, 1, 100]

plt.scatter(tm, vm)
for f_scale in f_scales:
    r = scipy.optimize.least_squares(error, [10, 10], loss='soft_l1', f_scale=f_scale)
    vp = f(smootht, *r.x)
    plt.plot(smootht, vp, label=f_scale)
plt.legend()

结果情节如下所示:

effect of f_scale

我的建议是在玩f_scale之前先尝试不同的损失功能。