使用浮点 NumPy 数组进行比较和相关操作

Working with floating point NumPy arrays for comparison and related operations

我有一组随机浮点数,我需要将它与另一个具有相同值但顺序不同的数组进行比较。就此而言,我使用总和、乘积(以及其他组合,具体取决于 table 的维度,因此需要方程的数量)。

然而,当我根据值的顺序对数组执行求和(或乘积)时遇到了精度问题。

这是一个简单的独立示例来说明这个问题:

import numpy as np

n = 10
m = 4

tag = np.random.rand(n, m)

s1 = np.sum(tag, axis=1)
s2 = np.sum(tag[:, ::-1], axis=1)

# print the number of times s1 is not equal to s2 (should be 0)
print np.nonzero(s1 != s2)[0].shape[0]

如果您执行此代码,它有时会告诉您 s1s2 不相等,并且差异在于计算机精度的大小。

问题是我需要在像 np.in1d 这样的函数中使用那些我无法真正给出容差的函数...

有没有办法避免这个问题?

对于列出的代码,您可以使用 np.isclose 并且也可以指定公差值。

使用提供的示例,让我们看看如何使用它 -

In [201]: n = 10
     ...: m = 4
     ...: 
     ...: tag = np.random.rand(n, m)
     ...: 
     ...: s1 = np.sum(tag, axis=1)
     ...: s2 = np.sum(tag[:, ::-1], axis=1)
     ...: 

In [202]: np.nonzero(s1 != s2)[0].shape[0]
Out[202]: 4

In [203]: (~np.isclose(s1,s2)).sum() # So, all matches!
Out[203]: 0

要在其他场景中使用公差值,我们需要根据具体情况进行工作。因此,假设对于涉及 np.in1d 中的逐元素比较的实现,我们可以引入 broadcasting 来对第一个输入中的所有元素与第二个输入中的所有元素进行元素相等检查。然后,我们使用 np.abs 得到 "closeness factor" 最后与输入容差进行比较以决定匹配。根据模拟 np.in1d 的需要,我们沿着其中一个轴进行任何操作。因此,使用 broadcasting 的公差 np.in1d 可以像这样实现 -

def in1d_with_tolerance(A,B,tol=1e-05):
    return (np.abs(A[:,None] - B) < tol).any(1)

正如 OP 评论中所建议的那样,我们还可以在按比例放大浮点数字后对其进行舍入,这应该是内存高效的,因为需要处理大型数组。所以,修改后的版本应该是这样的 -

def in1d_with_tolerance_v2(A,B,tol=1e-05):
    S = round(1/tol)
    return np.in1d(np.around(A*S).astype(int),np.around(B*S).astype(int))

示例 运行 -

In [372]: A = np.random.rand(5)
     ...: B = np.random.rand(7)
     ...: B[3] = A[1] + 0.0000008
     ...: B[6] = A[4] - 0.0000007
     ...: 

In [373]: np.in1d(A,B) # Not the result we want!
Out[373]: array([False, False, False, False, False], dtype=bool)

In [374]: in1d_with_tolerance(A,B)
Out[374]: array([False,  True, False, False,  True], dtype=bool)

In [375]: in1d_with_tolerance_v2(A,B)
Out[375]: array([False,  True, False, False,  True], dtype=bool)

最后,关于如何使其适用于其他实现和用例 - 这将取决于实现本身。但对于大多数情况,np.isclosebroadcasting 应该有所帮助。