代码之家  ›  专栏  ›  技术社区  ›  StefanS

scipy curve_fit仅对非常特定的x值无提示地失败

  •  3
  • StefanS  · 技术社区  · 6 年前

    我有一段更大的代码,它可以使函数与核心数据相匹配。要安装的数据和功能是动态的。最近我在整个系统中附加了一个额外的数据点,现在 curve_fit 无论我如何选择,始终返回初始猜测值(或与之太接近的值)。这发生在非常不同的y值和x值上(前者10组,后者2组)。

    我知道选择起始值很重要,但是我以前从未遇到过使用默认值的问题(我的函数通常很简单),并且可以通过取消注释添加附加数据点的新代码,恢复到它刚工作的状态。现在人们会认为新的代码显然是问题所在,但是在新的添加和实际向 曲线拟合 . 我已经检查了输入的类型 曲线拟合 是一样的: 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)的具有相同行为的例子。

    为了完整性起见,我添加的代码块(当我关闭此功能时,一切正常)。有趣的是,去掉了 local_z (由代码块添加的代码块)通过使用 local_z[:-1] 在MWE中不能解决问题。

    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.zf out.zh 是后来形成的向量吗? 洛拉尔兹 . 整个代码相当大,而且还依赖于netcdf文件(即 data 在上面的片段中)。我已经问过了 here 但那是为了工作代码。

    我很困惑,不知道如何解决这个问题,甚至不知道如何继续调试。copy与deepcopy之间是否可能存在问题或类似问题?尽管我想知道如何通过存储阵列将其传输到MWE…

    1 回复  |  直到 6 年前
        1
  •  5
  •   DSM    6 年前

    追踪这件事很有趣。-)

    不是价值观,而是他们 类型 . 这是一个精确的问题: 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.])
    

    但如果我们愿意,我们可以让本地的工作:

    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.])