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

nbewdwxp  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(92)

我只是拟合一个线性函数到一些数据,但遇到了curve_fit中默认初始值设置为1的问题。因此,我希望更改初始值,但代码必须非常通用,因为我希望将其应用于不同的y变量。所以我将截距值设置为前20个数据点的平均值,因为这应该非常接近最佳答案(我的x值偏移到0附近)。但是我使斜率为0,因为对于不同的变量,可能有任何符号关系,或者没有。
然而,在我的示例中,斜率为零,curve_fit不会改变此斜率-而是更改截距以最佳拟合数据,把它从它应该在的地方拉开。当值被改变为非零但仍然很小时,这种行为不会改变-在示例中,0.01和0.001具有相同的效果。当它不改变参数时,它会给出“无法估计参数的协方差”警告。
这些数据都是float 64,所以它与之前讨论的here问题没有直接关系。
我不确定这是否是最好的分享方式,但我已经上传了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()

字符串
x1c 0d1x的数据

ne5o7dgx

ne5o7dgx1#

对评论中提到的想法进行扩展:
如果你对数据进行缩放,使大多数点都在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)



(Note:这是在我将xs和ys都按xs排序之后。)
对于这个数据集,linregress()也比curve_fit()快20倍,因为curve_fit()更灵活。

相关问题