检查一个numpy数组中有多少个numpy数组与另一个不同大小的numpy数组中的其他numpy数组相等

6

我的问题

假设我有以下情况:

a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.array([9,10])])
b = np.array([ np.array([5,6]), np.array([1,2]), np.array([3,192])])

这是两个不同大小的数组,包含其他数组(内部数组具有相同的大小!)

我想计算b中的多少项(即内部数组)也在a中。请注意,我不考虑它们的位置!

我该怎么做呢?

我的尝试

count = 0
for bitem in b:
     for aitem in a:
         if aitem==bitem:
               count+=1

有更好的方法吗?特别是在一行中,也许使用一些理解力..

4
标题党,必须点赞。 - Mark Baijens
@谢谢,伙计,感激不尽。 - Euler_Salter
4个回答

3

numpy_indexed 包含了高效(通常为nlogn)和向量化的解决方案,用于这些类型的问题:

import numpy_indexed as npi
count = len(npi.intersection(a, b))

请注意,这与您的双重循环略有不同,例如丢弃a和b中的重复条目。如果您想保留b中的重复项,则可以使用以下方法:
count = npi.in_(b, a).sum()

在处理云中的重复条目时,也可以通过执行npi.count(a)并考虑其结果来处理。但是,无论如何,在这里我只是为了说明而胡言乱语,因为我想这种区别可能对您并不重要。


你认为这两种解决方案比上述的更快吗? - Euler_Salter
2
这些方法在内存和计算方面都是二次的;所以对于超过几个数组元素的任何情况,绝对不行。 - Eelco Hoogendoorn

2
这里有一个简单的方法来实现它:
a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.array([9,10])])
b = np.array([ np.array([5,6]), np.array([1,2]), np.array([3,192])])

count = np.count_nonzero(
    np.any(np.all(a[:, np.newaxis, :] == b[np.newaxis, :, :], axis=-1), axis=0))

print(count)
>>> 2

首先,count 不应该是2吗?输入中只有2个匹配的数组。你正在计算匹配元素(5、6、1、2和3),而不是匹配的数组((5,6)和(1,2))。 - Daniel F
另外,np.logical_or.reduce(.., axis = 0) 等同于 np.any( . . ., axis = 0),在布尔数组上使用 np.count_nonzero 相对于简单的 sum() 来说是浪费的。 - Daniel F
@DanielF 你说得对,我误读了问题,我以为它是关于一般的共同元素,而不是子数组。然而,在这里 count_nonzerosum 快得多(在 IPython 中检查 %timeit (np.random.rand(10000000) > .5).sum()%timeit np.count_nonzero(np.random.rand(10000000) > .5))。 - jdehesa

2
您可以使用以下一行代码来实现您想要的功能:
count = sum([np.array_equal(x,y) for x,y in product(a,b)])

解释

以下是发生的事情的解释:

  1. 使用itertools.product迭代两个数组,该函数将创建一个迭代器,用于遍历两个数组的笛卡尔积。
  2. 比较来自步骤1.的元组(x,y)中的每两个数组,使用np.array_equal
  3. 在列表上使用sum时,True等于1

完整示例:

最终代码如下:

import numpy as np 
from itertools import product 
a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.array([9,10])])
b = np.array([ np.array([5,6]), np.array([1,2]), np.array([3,192])])
count = sum([np.array_equal(x,y) for x,y in product(a,b)])
# output: 2

1
您可以将行转换为dtype = np.void,然后在生成的1d数组上使用np.in1d
def void_arr(a):
    return np.ascontiguousarray(a).view(np.dtype((np.void, a.dtype.itemsize * a.shape[1]))) 

b[np.in1d(void_arr(b), void_arr(a))]

array([[5, 6],
       [1, 2]])

如果您只想知道交点数量,那么这就是:
np.in1d(void_arr(b), void_arr(a)).sum()

2
注意:如果ba中有重复项,则np.in1d(void_arr(b), void_arr(a)).sum()可能不等于np.in1d(void_arr(a), void_arr(b)).sum()。我已经颠倒了原始答案的顺序,以匹配您的问题(即在a中有多少个元素在b中?)
要了解更多信息,请参见第三个答案here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接