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

数值非常小的Numpy数组运算精度

  •  2
  • JE_Muc  · 技术社区  · 6 年前

    我的数组操作的精度有点问题。我正在进行大量的数组计算,其中数组中的一些单元格必须被忽略,要么通过掩蔽,要么在这种情况下,通过在附近指定非常小的值来完成 np.finfo(float).tiny 要删除的数组单元格。
    但在阵列操作期间,这会导致大约 1e-14 这与机器ε非常接近。但我仍然不知道错误来自哪里,也不知道如何避免。由于我执行了数百万次这些操作,因此总的误差约为2-3%。
    以下是我的最低工作示例:

    arr = np.arange(20).astype(float)
    arr[0] = 1e-290
    t1 = np.random.rand(20) * 100
    t2 = np.random.rand(20) * 100
    a = (arr * (t1 - t2)).sum()
    b = (arr * (t1 - t2))[1:].sum()
    d = (arr * (t1 - t2))[0].sum()
    c = b - a
    print(c)
    # Out[99]: 4.5474735088646412e-13
    

    为了避免这个问题,我试图掩盖 arr :

    arr_mask = np.ma.masked_where(arr < 1e-200, arr)
    a_mask = (arr_mask * (t1 - t2)).sum()
    b_mask = (arr_mask * (t1 - t2))[1:].sum()
    c_mask = b_mask - a_mask
    print(c_mask)
    # Out[118]: 4.5474735088646412e-13
    

    为什么会有区别, c 如此多的量级大于 d ,应该有什么区别?我猜是机器epsilon的问题,从一开始就给数组分配了这么小的值?但仍然 np.finfo(float).eps 具有 2.2204460492503131e-16 大约比 c .
    我如何避免这种情况?将元素设置为零将不起作用,因为我有很多分区。在这种情况下,有几个原因我不能使用掩蔽。但必须忽略的细胞的位置永远不会改变。那么,我是否可以为这些单元格指定一个“安全”值,以便在更改整个数组操作的结果时将其忽略?
    提前感谢!

    1 回复  |  直到 6 年前
        1
  •  3
  •   Paul Panzer    6 年前

    给定浮点类型的粒度不是固定的,而是取决于从中开始的值的大小。我鼓励你玩 numpy.nextafter 功能:

    a = 1.5
    >>> np.nextafter(a, -1)
    1.4999999999999998
    >>> a - np.nextafter(a, -1)
    2.220446049250313e-16
    >>> a = 1e20
    >>> np.nextafter(a, -1)
    9.999999999999998e+19
    >>> a - np.nextafter(a, -1)
    16384.0
    

    这表明,通过从 a 取决于大小

    现在,您应该能够计算出示例中发生了什么