我有一组随机 float ,我需要将它与另一个具有相同值但顺序不同的数组进行比较。就此而言,我使用总和、乘积(以及其他组合,具体取决于表格的尺寸,因此需要方程的数量)。
然而,当我根据值的顺序对数组执行求和(或乘积)时遇到了精度问题。
这是一个简单的独立示例来说明这个问题:
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]
如果您执行此代码,它有时会告诉您 s1
和 s2
不相等,并且计算机精度的差异很大。
问题是我需要在像 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
获取“接近因子”,最后与输入容差进行比较以确定匹配项。根据模拟 np.in1d
的需要,我们沿着其中一个轴进行任何操作。因此,可以像这样实现使用 broadcasting
的容差 np.in1d
-
def in1d_with_tolerance(A,B,tol=1e-05):
return (np.abs(A[:,None] - B) < tol).any(1)
正如 OP 的评论中所建议的,我们还可以在按比例放大后舍入 float 字,这应该是内存高效的,因为需要处理大型数组。所以,修改后的版本应该是这样的——
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))
sample 运行-
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.isclose
和 broadcasting
应该会有所帮助。
关于python - 使用浮点 NumPy 数组进行比较和相关操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39757559/