检查两个数组是否具有等效行的最快方法
我正在寻找一种更好的方法来检查两个二维数组是否包含相同的行。下面是一个简单的例子:
>>> a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
>>> b
array([[6, 7, 8],
[3, 4, 5],
[0, 1, 2]])
在这个例子中,b=a[::-1]
。要检查两行是否相等:
>>>a=a[np.lexsort((a[:,0],a[:,1],a[:,2]))]
>>>b=b[np.lexsort((b[:,0],b[:,1],b[:,2]))]
>>> np.all(a-b==0)
True
这个方法很好,而且速度也比较快。不过,当两行“接近”时,就会出现问题:
array([[-1.57839867 2.355354 -1.4225235 ],
[-0.94728367 0. -1.4225235 ],
[-1.57839867 -2.355354 -1.4225215 ]]) <---note ends in 215 not 235
array([[-1.57839867 -2.355354 -1.4225225 ],
[-1.57839867 2.355354 -1.4225225 ],
[-0.94728367 0. -1.4225225 ]])
在容差为1E-5的情况下,这两个数组按行来看是相等的,但使用字典排序(lexsort)却会得出不同的结果。这个问题可以通过改变排序顺序来解决,但我希望能找到一个更通用的方法。
我在考虑以下想法:
a=a.reshape(-1,1,3)
>>> a-b
array([[[-6, -6, -6],
[-3, -3, -3],
[ 0, 0, 0]],
[[-3, -3, -3],
[ 0, 0, 0],
[ 3, 3, 3]],
[[ 0, 0, 0],
[ 3, 3, 3],
[ 6, 6, 6]]])
>>> np.all(np.around(a-b,5)==0,axis=2)
array([[False, False, True],
[False, True, False],
[ True, False, False]], dtype=bool)
>>>np.all(np.any(np.all(np.around(a-b,5)==0,axis=2),axis=1))
True
这个方法并不能告诉你数组是否按行相等,只能告诉你b
中的所有点是否接近a
中的某个值。行数可能有几百,而且我需要频繁进行这样的检查。有没有什么好的建议?
1 个回答
1
你最后写的代码并没有达到你想要的效果。它实际上是在告诉你,数组b中的每一行是否都接近数组a中的某一行。如果你改变一下在外部调用np.any和np.all时使用的axis参数,你就可以检查数组a中的每一行是否接近数组b中的某一行。如果数组b中的每一行都接近数组a中的某一行,同时数组a中的每一行也都接近数组b中的某一行,那么这两个集合就是相等的。虽然这样做可能不是很高效,但在处理中等大小的数组时,使用numpy可能会非常快:
def same_rows(a, b, tol=5) :
rows_close = np.all(np.round(a - b[:, None], tol) == 0, axis=-1)
return (np.all(np.any(rows_close, axis=-1), axis=-1) and
np.all(np.any(rows_close, axis=0), axis=0))
>>> rows, cols = 5, 3
>>> a = np.arange(rows * cols).reshape(rows, cols)
>>> b = np.arange(rows)
>>> np.random.shuffle(b)
>>> b = a[b]
>>> a
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])
>>> b
array([[ 9, 10, 11],
[ 3, 4, 5],
[ 0, 1, 2],
[ 6, 7, 8],
[12, 13, 14]])
>>> same_rows(a, b)
True
>>> b[0] = b[1]
>>> b
array([[ 3, 4, 5],
[ 3, 4, 5],
[ 0, 1, 2],
[ 6, 7, 8],
[12, 13, 14]])
>>> same_rows(a, b) # not all rows in a are close to a row in b
False
对于不太大的数组来说,性能是可以接受的,尽管它需要构建一个形状为(行数, 行数, 列数)的数组:
In [2]: rows, cols = 1000, 10
In [3]: a = np.arange(rows * cols).reshape(rows, cols)
In [4]: b = np.arange(rows)
In [5]: np.random.shuffle(b)
In [6]: b = a[b]
In [7]: %timeit same_rows(a, b)
10 loops, best of 3: 103 ms per loop