问题 在Python中查找两个大型数组(矩阵)之间的集合差异


我有两个大的二维数组,我想找到它们的集合差异,将它们的行作为元素。在Matlab中,这个代码就是 setdiff(A,B,'rows')。数组足够大,我想到的明显的循环方法需要花费太长时间。


5322
2017-08-10 13:50


起源

“设定差异”是什么意思? - reptilicus
@ user1443118我猜他的意思是“A中的值不在B中”。按照 mathworks.com/help/techdoc/ref/setdiff.html。 - Hooked
“设定差异”如“设定差异”设定理论操作? - Pablo Santa Cruz
你的二维阵列怎么样?列表清单? - Pablo Santa Cruz
阵列的尺寸是否相同? - reptilicus


答案:


这个 应该 工作,但由于正在创建的视图的mergesort不可用,因此目前在1.6.1中已中断。它适用于1.7.0之前的版本。这应该是最快的方法,因为视图不必复制任何内存:

>>> import numpy as np
>>> a1 = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> a2 = np.array([[4,5,6],[7,8,9],[1,1,1]])
>>> a1_rows = a1.view([('', a1.dtype)] * a1.shape[1])
>>> a2_rows = a2.view([('', a2.dtype)] * a2.shape[1])
>>> np.setdiff1d(a1_rows, a2_rows).view(a1.dtype).reshape(-1, a1.shape[1])
array([[1, 2, 3]])

你可以用Python做到这一点,但它可能很慢:

>>> import numpy as np
>>> a1 = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> a2 = np.array([[4,5,6],[7,8,9],[1,1,1]])
>>> a1_rows = set(map(tuple, a1))
>>> a2_rows = set(map(tuple, a2))
>>> a1_rows.difference(a2_rows)
set([(1, 2, 3)])

9
2017-08-10 14:05



谢谢。底部方法最终崩溃了,但是一旦我弄清楚如何安装新版本的numpy,我将尝试使用top方法。 - zss


这是一个很好的替代纯numpy解决方案,适用于1.6.1。它确实创建了一个中间数组,因此这对您来说可能是也可能不是问题。它也不依赖于排序数组的任何加速(如 setdiff 可能吗)。

from numpy import *
# Create some sample arrays
A =random.randint(0,5,(10,3))
B =random.randint(0,5,(10,3))

举个例子,这就是我得到的 - 请注意,有一个共同的元素:

>>> A
array([[1, 0, 3],
       [0, 4, 2],
       [0, 3, 4],
       [4, 4, 2],
       [2, 0, 2],
       [4, 0, 0],
       [3, 2, 2],
       [4, 2, 3],
       [0, 2, 1],
       [2, 0, 2]])
>>> B
array([[4, 1, 3],
       [4, 3, 0],
       [0, 3, 3],
       [3, 0, 3],
       [3, 4, 0],
       [3, 2, 3],
       [3, 1, 2],
       [4, 1, 2],
       [0, 4, 2],
       [0, 0, 3]])

我们寻找行之间的(L1)距离为零。这给了我们一个矩阵,在它为零的点上,这些是两个列表共有的项:

idx = where(abs((A[:,newaxis,:] - B)).sum(axis=2)==0)

作为检查:

>>> A[idx[0]]
array([[0, 4, 2]])
>>> B[idx[1]]
array([[0, 4, 2]])

5
2017-08-10 14:46



downvoter可以解释一下吗?我欢迎任何批评或评论如何改进。 - Hooked
谢谢你聪明的代码(我会记得newaxis的配方)。不幸的是,当我尝试它时,我得到了错误:“ValueError:数组太大了。” - zss
@ user1590405运行时 A.size() 和 B.size() 阵列有多大? - Hooked


我不确定你的目的是什么,但这会得到一个布尔数组,其中2个数组不相等,并且将快速numpy:


import numpy as np
a = np.random.randn(5, 5)
b = np.random.randn(5, 5)
a[0,0] = 10.0
b[0,0] = 10.0 
a[1,1] = 5.0
b[1,1] = 5.0
c = ~(a-b==0)
print c

[[False True True True True]  [真假真真真]  [真如真真实]  [真如真真实]  [True True True True]]


-1
2017-08-10 14:28



这是不正确的,它比较了元素。 OP正在寻找设置差异 行。 - Hooked
为了上帝的缘故,ROWS由ELEMENTS组成。 a [0,c [0]]给出不在b中的0行中的元素。 - reptilicus
这是真的“a[0, c[0]] 给出了一个不在b“的0行中的元素,但是我读这个问题的方式并不是每行都找到相同的A和B的元素,而是找到 行 A和 行 B匹配。 - Hooked
但是,从匹配矩阵中,您可以轻松地转到使用的行匹配的数组 np.all(match_matrix, axis=0) 然而。 - Okarin