曲线拟合过于依赖初始参数

问题描述 投票:0回答:1

我一直在尝试使用 scipy.curve_fit 来拟合曲线,但它似乎坚持一些局部最小值(非常接近初始参数猜测)并且不尝试任何其他组合。通常在 100-200 次迭代后停止。 正如你所看到的,这种配合通常很糟糕。 预期的形状是:短恒线、斜线、(可选恒线)、斜线向下、短恒线

def piecewise_linear(X, x1, x2, x22, x3, y1, y2, y3):
    return  np.piecewise(X,  [(X < x1), (x1 <= X) & (X < x2), (x2 <= X) & (X <= x22), (x22 < X) & (X < x3), X >= x3],
                  [lambda X: y1, lambda X: y1 + (y2 - y1) / (x2 - x1) * (X - x1),
                  lambda X: y2, lambda X: y2 + (y3 - y2) / (x3 - x22) * (X - x22), lambda X: y3])  

for i in range(num of vectors): 
    bounds = ([0, global_min_left_x, global_max_x, global_max_x,  -np.inf, -np.inf,-np.inf],
              [global_max_x, global_max_x, global_min_right_x, vector_length, np.inf,np.inf, np.inf])
    additional_kwargs = {'method': 'dogbox', 'ftol': 1e-15, 'xtol': 1e-15, 'maxfev': 100000}
    params, _ = curve_fit(piecewise_linear, X, Z, bounds=bounds,
                         p0=(global_min_left_x, global_max_x,global_max_x, global_min_right_x,
                                          global_min_left_z, global_max_z, global_min_right_z),
                                      **additional_kwargs)

    fitted_curve = [piecewise_linear(x, *params) for x in X]

Fit example

也许解决方案是设置正确的 kwargs(说实话,我不确定我是否理解正确)。我也尝试过不同的p0,但问题是一样的——几乎没有拟合,基本上只是连接了p0点。

也许查看我想要拟合的数据可能有用,所以有一个例子 https://pastebin.com/f0xF9fsd

python python-3.x curve-fitting scipy-optimize
1个回答
0
投票

您遇到了缩放问题,您发布的数据的缩放比例为 1e-8,这混淆了优化算法。

您必须首先重新调整数据,然后由于此优化可能陷入局部最小值,因此您应该尝试从随机初始点重新启动它。我在您发布的数据上尝试了以下代码(使用您的符号,第一列是

X
,第二列是
Z
,函数
piecewise_linear
保留为您定义的):

ntrials = 1000
nparams = 7  # number of parameters to optimize

scale = max(max(abs(X)), max(abs(Z)))
print(f'scale: {scale}')
X = X / scale
Z = Z / scale

min_err = np.inf
best_params = None
for i in range(ntrials):
    try:
        params, stats = curve_fit(piecewise_linear, X, Z,
                                  p0=np.random.randn(nparams))
    except:
        # Ignores RuntimeError: Optimal parameters not found:
        # Number of calls to function has reached maxfev
        continue
    fitted_curve = [piecewise_linear(x, *params) for x in X]
    err = np.mean(np.square(Z - fitted_curve))
    # print(f'i: {i}: {err}')
    if err < min_err:
        min_err = err
        best_params = params

打印

scale
显示大约 6e-8,如果需要,您可以将参数与此相乘以缩小它们。 1000 次试验的最佳参数给出了重新调整后的数据的均方误差约为 4e-6,并且曲线良好:

© www.soinside.com 2019 - 2024. All rights reserved.