如何通过另一个数组过滤一个 numpy 点数组

How to filter a numpy array of points by another array

如何通过 numpy 数组 b 的元素过滤 numpy 数组 a,以便获得 a 中不在 b 中的所有点。

import numpy as np

a = np.array([[1,2],[1,3],[1,4]])
b = np.array([[1,2],[1,3]])
c = np.array([ d for d in a if d not in b])
print(c)

# acutall outcome
# []
# desired outcome
# np.array([[1,4]])```

这可能不是最有效的(尽管事实证明它比此处针对此输入提供的其他方法更快——见下文),但您可以做的一件事是转换 ab 到 Python 列表然后取它们的集合差:

# Method 1
tmp_1 = [tuple(i) for i in a]    # -> [(1, 2), (1, 3), (1, 4)]
tmp_2 = [tuple(i) for i in b]    # -> [(1, 2), (1, 3)]

c = np.array(list(set(tmp_1).difference(tmp_2)))

正如@EmiOB 所指出的, 提供了一些关于为什么 [ d for d in a if d not in b ] 在你的问题中不起作用的见解。从 post 中提取,您可以使用

# Method 2
c = np.array([d for d in a if all(any(d != i) for i in b)])

备注


The implementation of array_contains(PyArrayObject *self, PyObject *el)(在 C 中)表示调用 array_contains(self, el)(在 C 中)等同于

(self == el).any()

在Python中, 其中 self 是指向数组的指针,el 是指向 Python 对象的指针。

换句话说:

  1. 如果 arr 是一个 numpy 数组并且 obj 是某个任意的 Python 对象,那么
obj in arr

相同
(arr == obj).any()
  1. 如果arr是典型的Python容器,如列表、元组、字典等,则
obj in arr

相同
any(obj is _ or obj == _ for _ in arr)

(参见 membership test operations)。

综上所述,obj in arr的含义因arr的类型而异。

这就解释了为什么你提出的逻辑理解[d for d in a if d not in b]没有达到预期的效果。

这可能会造成混淆,因为人们很容易推断,既然 numpy 数组是一个序列(尽管不是标准的 Python 序列),测试成员语义应该是相同的。事实并非如此。

示例:

a = np.array([[1,2],[1,3],[1,4]])
print((a == [1,2]).any())          # same as [1, 2] in a
# outputs True

计时


对于您的输入,我发现我的方法是最快的,其次是从 post @EmiOB 建议的方法 2 中获得的方法,然后是 @DanielF 的方法。如果更改输入大小会改变时间顺序,我不会感到惊讶,所以请对它们持保留态度。

# Method 1
5.96 µs ± 8.92 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
# Method 2
6.45 µs ± 27.5 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
# @DanielF's answer
16.5 µs ± 276 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

使用这个:

c = np.array([a_elem for a_elem in a if all(any(a_elem != b_elem) for b_elem in b)])

输出:

array([[1, 4]])

解释:

我们从 a 中循环查找子列表 a_elem,并检查 b 中的所有子列表。 any(a_elem != b_elem) returns True 如果 a_elem 中的任何值不等于 b_elemall(any(a_elem != b_elem) for b_elem in b) returns 如果所有子列表不相等则为真。

例如:

我们从 a 中取出 [1,2] 检查它的 任何 元素是否不等于 [1,2], [1,3] 来自 b 一一。因此,[1,2]False[1,3]True。这将创建一个列表 [False, True]

接下来,我们从 a 中取出 [1,3][1,2] 为 return True[1,3]False。这将创建另一个列表 [True, False].

最后,我们从 a 中取出 [1,4][1,2][1,3] 都会 return True。这将创建一个列表 [True, True]

现在,当我们 运行 all() 它 returns True 当上面列表中的两个值都是 True 时。因此,我们将 [1,4] 添加到数组中。

当像这样比较 row-wise 时,我倾向于使用 @Jaime 的方法来转换为无效视图 here :

vview = lambda a:np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1])))

a[~np.isin(vview(a), vview(b)).squeeze()]
Out[]: array([[1, 4]])

这避免了其他答案的缓慢 for 循环,并且不会创建任何中间数据结构。