【问题标题】:Find the set difference between two large arrays (matrices) in Python在 Python 中查找两个大型数组(矩阵)之间的集差
【发布时间】:2012-08-07 20:08:51
【问题描述】:

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

【问题讨论】:

  • “设置差异”是什么意思?
  • @user1443118 我猜他的意思是“A 中的值不在 B 中”。根据mathworks.com/help/techdoc/ref/setdiff.html
  • “设置差异”如“设置差异”中的集合论操作?
  • 你的二维数组是什么样子的?列表列表?
  • 数组的维度是否相同?

标签: python numpy set-difference


【解决方案1】:

应该工作,但目前在 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)])

【讨论】:

  • 谢谢。 bottom 方法最终崩溃了,但是一旦我弄清楚如何安装新版本的 numpy 我会尝试 top 方法。
【解决方案2】:

我不确定你要做什么,但这会给你一个布尔数组,其中 2 个数组不相等,并且会很快:


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 False True True True] [ True True True True True] [ True True True True True] [ True True True True True]]

【讨论】:

  • 这是不正确的,它比较了元素。 OP 正在寻找 rows 的设置差异。
  • 确实“a[0, c[0]] 给出了 a 的第 0 行中的元素不在 b 中”,但我阅读问题的方式不是找到每行 A 和 B 的元素相同,但要找到匹配的 A 的 rows 和 B 的 rows
  • 然而,您可以从匹配矩阵轻松转到使用np.all(match_matrix, axis=0) 提供行匹配的数组。
【解决方案3】:

这是一个不错的替代纯 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]])

【讨论】:

  • 投反对票的能解释一下吗?欢迎对如何改进提出任何批评或意见。
  • 感谢聪明的代码(我会记住 newaxis 公式)。不幸的是,当我尝试它时,我得到了错误:“ValueError:数组太大。”
  • @user1590405 当你运行A.size()B.size() 时,数组有多大?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
  • 2022-01-04
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
  • 2014-01-05
  • 1970-01-01
相关资源
最近更新 更多