Scipy curve_fit仅对非常特定的x值默默失败

时间:2018-09-18 15:29:19

标签: python numpy scipy curve-fitting

我有一段更大的代码,其功能适合于数据的核心。数据和要安装的功能是动态的。最近,我在整个系统上附加了一个额外的数据点,现在curve_fit总是返回初始猜测(或与它太接近的东西),无论我如何选择。 y值和x值完全不同(前者为10套,后者为2套)时,会发生这种情况。

我知道选择起始值很重要,但是我以前从未使用默认值(我的功能通常很简单),并且可以通过取消注释添加了额外数据的新代码来恢复到它可以工作的状态点。现在,人们会认为新代码显然是问题所在,但是在新添加内容和实际将数据馈送到curve_fit之间有很多步骤。我已经检查过curve_fit的输入类型是否相同:np.ndarray,在有问题的情况下只增加了一个元素。

但是,在创建MWE时,我注意到仅是导致问题的确切X数组。当我在MWE中复制主程序的打印x矢量而不是内部表示时,它完全消失了。因此,我只能通过外部文件来显示问题:local_z.npy [150kB]

MWE:

import numpy as np
from scipy.optimize import curve_fit

values = np.array([[1.37712972, 1.58475346, 1.78578759, 1.9843099,  1.73393093],
                   [-0.0155715,  -0.01534987, -0.00910744, -0.00189728, -1.73393093],
                   [1.23613934, 0.76894505, 0.18876817, 0.06376843, 1.1637315 ],
                   [0.8535248,  0.53093829, 0.13033993, 0.04403058, 0.80352895],
                   [0.51505805, 0.32039379, 0.0786534,  0.02657018, 0.48488813]])
heights = np.array([ 22.110203,  65.49054,  110.321526, 156.54034,  166.59094])
local_z = np.load('local_z.npy')
print('difference in heights', local_z - heights)

def func(z, a0, a1):
    return a0 + a1*z

for v in values:
    popt_non_working = curve_fit(func, local_z, v)[0]
    print('not working: ', popt_non_working)
    popt_working = curve_fit(func, heights, v)[0]
    print('working: ', popt_working)

我在Python 2.7.6,numpy 1.14.1和scipy 1.0.0中的输出:

$ python auxiliary/SUBLIME_fit_test.py  
('difference in heights', array([-2.10693358e-07, -4.49218746e-07, -4.26269537e-07,  4.23828126e-06, 2.38281251e-06]))
/home/csag5117/venv/local/lib/python2.7/site-packages/scipy/optimize/minpack.py:785: OptimizeWarning: Covariance of the parameters could not be estimated category=OptimizeWarning)
('not working: ', array([1., 1.]))
('working: ', array([1.35420488, 0.00325281]))
('not working: ', array([1., 1.]))
('working: ', array([ 0.38896878, -0.00714073]))
('not working: ', array([1., 1.]))
('working: ', array([ 1.06301278, -0.00363439]))
('not working: ', array([1., 1.]))
('working: ', array([ 0.73398503, -0.00250946]))
('not working: ', array([1., 1.]))
('working: ', array([ 0.442922  , -0.00151433]))

如您所见,我使用heights作为x值的版本按预期工作(返回拟合参数),而我使用存储的`local_z'的版本却不起作用,即使两者之间存在差异两个阵列之间的距离很小。 我仅显示多个y值,以表明这不是百万分之一的故障,可以通过适当的起始值来解决。这只是一个示例,我也有一个具有更多数据点(24个而不是5个)的相同行为。

出于完整性考虑,我添加了代码块(当我关闭此功能后,一切正常)。有趣的是,通过在MWE中使用local_z忽略了local_z[:-1]中的最后一个值(这是代码块添加的值)并不能解决问题。

zi_minus_dd -= 1
zf_long = np.append(out.zf, np.squeeze(data.zf[t])[z_mask_full[-1] + 1])
u_zi = np.interp(zi_minus_dd, zf_long,
    np.append(out.u, np.squeeze(data.u[t])[z_mask_full[-1] + 1]))
v_zi = np.interp(zi_minus_dd, zf_long,
    np.append(out.v, np.squeeze(data.v[t])[z_mask_full[-1] + 1]))
th_zi = np.interp(zi_minus_dd, zf_long,
    np.append(out.th, np.squeeze(data.th[t])[z_mask_full[-1] + 1]))

zh_long = np.append(out.zh, np.squeeze(data.zh[t])[z_mask_full[-1] + 1])
uw_zi = np.interp(zi_minus_dd, zf_long,
    np.append(out.uw_raw, np.squeeze(data.uw[t])[z_mask_full[-1] + 1]))
vw_zi = np.interp(zi_minus_dd, zf_long,
    np.append(out.vw_raw, np.squeeze(data.vw[t])[z_mask_full[-1] + 1]))
tke_zi = np.interp(zi_minus_dd, zf_long,
    np.append(out.tke, np.squeeze(data.TKE[t])[z_mask_full[-1] + 1]))

out.zf = np.append(out.zf, zi_minus_dd)
out.u = np.append(out.u, u_zi)
out.v = np.append(out.v, u_zi)
out.th = np.append(out.th, u_zi)

out.zh = np.append(out.zh, zi_minus_dd)
out.uw_raw = np.append(out.uw_raw, u_zi)
out.vw_raw = np.append(out.vw_raw, u_zi)
out.tke = np.append(out.tke, u_zi)

out.zfout.zh是后来被制作成local_z的向量。 整个代码相当大,并且还取决于netCDF文件(以上代码段中的data)。我已经问过here,但这是为了工作代码。

我很困惑,不知道该如何解决甚至继续调试。复制vs深度复制是否可能存在问题或类似问题?虽然我不知道该如何通过存储的数组将其转移到MWE ...

1 个答案:

答案 0 :(得分:5)

对此进行跟踪很有趣。 :-)

不是值,而是它们的类型。这是一个精度问题:heights有效,它是float64,无效的local_z仅是float32。

我们有

In [70]: heights
Out[70]: array([ 22.110203,  65.49054 , 110.321526, 156.54034 , 166.59094 ])

In [71]: heights.dtype
Out[71]: dtype('float64')

In [72]: curve_fit(func, heights, v)[0]
Out[72]: array([1.35420488, 0.00325281])

In [73]: local_z
Out[73]: 
array([ 22.110205,  65.49054 , 110.321526, 156.54034 , 166.59094 ],
      dtype=float32)

In [74]: curve_fit(func, local_z, v)[0]
C:\Python\lib\site-packages\scipy\optimize\minpack.py:794: OptimizeWarning: Covariance of the parameters could not be estimated
  category=OptimizeWarning)
Out[74]: array([1., 1.])

但是,如果我们愿意,我们可以使local_z工作:

In [75]: curve_fit(func, local_z.astype(np.float64), v)[0]
Out[75]: array([1.35420488, 0.00325281])

或高度失败:

In [76]: curve_fit(func, heights.astype(np.float32), v)[0]
C:\Python\lib\site-packages\scipy\optimize\minpack.py:794: OptimizeWarning: Covariance of the parameters could not be estimated
  category=OptimizeWarning)
Out[76]: array([1., 1.])