使用 SciPy 的 least_squares() 进行曲线拟合
Curve fitting with SciPy's least_squares()
我正在使用 Python 进行最小二乘曲线拟合并获得不错的结果,但希望它更稳健一些。
我有来自一阶 LTI 系统的数据,更具体地说是测速仪读取的电机速度。我正在尝试拟合电机的阶跃响应,因此我可以推断出它的传递函数。
速度 (v(t)) 具有以下形式:
v(t) = K * (1 - exp(-t/T))
虽然我使用的数据中有一些异常值,但我想减轻它们。这主要发生在速度变得恒定时。假设速度是 10000 个单位,我有时会得到 10000 +/- 400 的异常值。我想知道如何设置我的 f_scale 参数,因为我希望我的数据点保持在 [=25= 的 +/- 400 以内] 速度(平均)。我应该将 f_scale 设置为 400 还是 800?我不确定我应该在那里设置什么。
谢谢
编辑:一些数据。
我构建了一个最小示例,它适用于类似于您的曲线。如果您发布的是实际数据而不是图片,速度会更快一些。关于 least_squares
稳健拟合要理解的两个关键是,您必须为 loss
参数使用不同于线性的值,并且 f_scale
用作损失的缩放参数功能。
基本上,根据文档,least_squares
尝试
minimize F(x) = 0.5 * sum(rho(f_i(x)**2)
并设置lossloss
参数改变了上面公式中的rho
。对于 loss='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()
结果图如下所示:
我的建议是先尝试不同的损失函数,然后再使用 f_scale
。
我正在使用 Python 进行最小二乘曲线拟合并获得不错的结果,但希望它更稳健一些。
我有来自一阶 LTI 系统的数据,更具体地说是测速仪读取的电机速度。我正在尝试拟合电机的阶跃响应,因此我可以推断出它的传递函数。
速度 (v(t)) 具有以下形式: v(t) = K * (1 - exp(-t/T))
虽然我使用的数据中有一些异常值,但我想减轻它们。这主要发生在速度变得恒定时。假设速度是 10000 个单位,我有时会得到 10000 +/- 400 的异常值。我想知道如何设置我的 f_scale 参数,因为我希望我的数据点保持在 [=25= 的 +/- 400 以内] 速度(平均)。我应该将 f_scale 设置为 400 还是 800?我不确定我应该在那里设置什么。
谢谢
编辑:一些数据。
我构建了一个最小示例,它适用于类似于您的曲线。如果您发布的是实际数据而不是图片,速度会更快一些。关于 least_squares
稳健拟合要理解的两个关键是,您必须为 loss
参数使用不同于线性的值,并且 f_scale
用作损失的缩放参数功能。
基本上,根据文档,least_squares
尝试
minimize F(x) = 0.5 * sum(rho(f_i(x)**2)
并设置lossloss
参数改变了上面公式中的rho
。对于 loss='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()
结果图如下所示:
我的建议是先尝试不同的损失函数,然后再使用 f_scale
。