scipy curve_fit 不会根据初始值改变某些参数

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

我只是将线性函数拟合到一些数据,但遇到了在 curve_fit 中将默认初始值设置为 1 的问题。因此,我希望更改初始值,但代码必须非常通用,因为我希望将其应用于不同的 y 变量。因此,我将截距值设置为前 20 个数据点的平均值,因为这应该非常接近最佳答案(我的 x 值偏移到接近 0 的位置)。但我把斜率设为0,因为不同的变量可能有符号关系,也可能没有。

但是,在我的示例中,斜率为零,curve_fit 不会改变该斜率 - 而是更改截距以最适合数据,将其拉离实际位置。当值更改为非零但仍然很小时,这种行为不会改变 - 在示例中 0.01 和 0.001 具有相同的效果。当它不改变参数时,它会给出“无法估计参数的协方差”警告。

数据都是float64,所以与之前讨论的问题没有直接关系这里

我不确定这是否是最好的分享方式,但我已将数据上传到 DropBox here。下面的代码以及这些数据应该会重现该问题。我的scipy版本是1.11.3.

感谢任何关于为什么会发生这种情况的想法!

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import pickle

def fit1(x, alpha, beta_t):
    yhat = alpha + beta_t*x
    return yhat


with open('example_data.pkl', 'rb') as handle:
    xs, ys = pickle.load(handle)
    
plt.plot(xs, ys, color='blue')

for guess in [0, 0.001, 0.01, 0.1, 1, 10]:
        
    init_guess = np.zeros(2)
    init_guess[0] = np.mean(ys[:20])
    init_guess[1] = guess
    params, _ = curve_fit(fit1, xs, ys, p0=init_guess)
    
    plt.plot(xs, fit1(xs, *params), label=f'init_guess[1] = {init_guess[1]}')


plt.legend()

python numpy scipy curve-fitting
1个回答
0
投票

扩展评论中提到的想法:

如果缩放数据以使大多数点都在 1 左右,则可以消除无法估计协方差的错误,并且无论初始猜测是什么,都可以拟合线性回归。

    params, _ = curve_fit(fit1, xs, ys/1e9, p0=init_guess)
    plt.plot(xs, fit1(xs, *params) * 1e9, label=f'init_guess[1] = {init_guess[1]}')

您还可以使用 StandardScaler 而不是乘以和除以常数。

或者,如果您使用 scipy.stats.linregress(),它可以直接找到解决方案,无需初始猜测或缩放:

res = scipy.stats.linregress(xs, ys)
plt.plot(xs, ys, color='blue')
plt.plot(xs, res.intercept + res.slope*xs)

(注:这是我将xs和ys都按xs排序后的结果。)

对于该数据集,linregress() 也比 curve_fit() 快 20 倍左右,因为 curve_fit() 更灵活。

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