Python 如何在3d numpy数组中查找2d数组的行

Python 如何在3d numpy数组中查找2d数组的行,python,arrays,numpy,Python,Arrays,Numpy,我试图找到一行,其中一个二维数组出现在一个三维数组中。这里有一个例子来说明我的意思。给出: arr = [[[0, 3], [3, 0]], [[0, 0], [0, 0]], [[3, 3], [3, 3]], [[0, 3], [3, 0]]] 我想查找以下所有事件: [[0, 3], [3, 0]] 我想要的结果是: [0, 3] 我试着使用argwhere,但不幸的是,我什么也没用。有什么想法吗?试试看 np.argwhere(np.all

我试图找到一行,其中一个二维数组出现在一个三维数组中。这里有一个例子来说明我的意思。给出:

arr = [[[0, 3], [3, 0]],
       [[0, 0], [0, 0]],
       [[3, 3], [3, 3]],
       [[0, 3], [3, 0]]]
我想查找以下所有事件:

[[0, 3], [3, 0]]
我想要的结果是:

[0, 3]
我试着使用
argwhere
,但不幸的是,我什么也没用。有什么想法吗?

试试看

np.argwhere(np.all(arr==[[0,3], [3,0]], axis=(1,2)))

工作原理:

arr==[[0,3],[3,0]]
返回

array([[[ True,  True],
        [ True,  True]],

       [[ True, False],
        [False,  True]],

       [[False,  True],
        [ True, False]],

       [[ True,  True],
        [ True,  True]]], dtype=bool)
这是一个三维数组,其中最里面的轴是2。该轴上的值为:

[True, True]
[True, True]
[True, False]
[False, True]
[False, True]
[True, False]
[True, True]
[True, True]
现在使用
np.all(arr==[[0,3],[3,0]],axis=2)
检查一行上的两个元素是否都是
True
,其形状将从(4,2,2)减少到(4,2)。像这样:

array([[ True,  True],
       [False, False],
       [False, False],
       [ True,  True]], dtype=bool)
您还需要进行一个步骤的缩减,因为您希望两者都相同(都是
[0,3]
[3,0]
。您可以通过在结果上进行缩减(现在最里面的轴是1):

或者,您也可以通过为axis参数提供一个元组来逐步执行相同的操作(首先是最内部的,然后是更高的一步)。结果将是:

array([ True, False, False,  True], dtype=bool)

在中,您可以在定义新数据类型后使用
np.in1d
,该数据类型将具有
arr
中每行的内存大小。要定义此类数据类型:

mydtype = np.dtype((np.void, arr.dtype.itemsize*arr.shape[1]*arr.shape[2]))
然后,您必须将
arr
转换为一维数组,其中每行都有
arr.shape[1]*arr.shape[2]
元素:

aView = np.ascontiguousarray(arr).flatten().view(mydtype)
现在,您已经准备好查找二维阵列模式
[[0,3],[3,0]]
,该模式还必须转换为
dtype

bView = np.array([[0, 3], [3, 0]]).flatten().view(mydtype)
您现在可以在
aView
中检查
bView
的出现情况:

np.in1d(aView, bView)
#array([ True, False, False,  True], dtype=bool)
使用
np可以轻松地将此掩码转换为索引。例如,其中

时间安排(更新) 以下功能用于实现此方法:

def check2din3d(b, a):
        """
        Return where `b` (2D array) appears in `a` (3D array) along `axis=0`
        """
        mydtype = np.dtype((np.void, a.dtype.itemsize*a.shape[1]*a.shape[2]))
        aView = np.ascontiguousarray(a).flatten().view(mydtype)
        bView = np.ascontiguousarray(b).flatten().view(mydtype)
        return np.in1d(aView, bView)
考虑到@ayhan评论的更新计时表明,该方法可以比np.argwhere更快,但差异并不显著,对于如下所示的大型阵列,@ayhan的方法要快得多:

arrLarge = np.concatenate([arr]*10000000)
arrLarge = np.concatenate([arrLarge]*10, axis=2)

pattern = np.ascontiguousarray([[0,3]*10, [3,0]*10])

%timeit np.argwhere(np.all(arrLarger==pattern, axis=(1,2)))
#1 loops, best of 3: 2.99 s per loop

%timeit check2din3d(pattern, arrLarger)
#1 loops, best of 3: 4.65 s per loop

包中的“contains”函数(免责声明:我是它的作者)可以用来进行此类查询。它实现了一个类似于Saullo提供的解决方案

import numpy_indexed as npi
test = [[[0, 3], [3, 0]]]
# check which elements of arr are present in test (checked along axis=0 by default)
flags = npi.contains(test, arr)
# if you want the indexes:
idx = np.flatnonzero(flags)

太棒了!!轴的整个概念让我很困惑。你能解释一下为什么轴=(1,2)工作?当然,我会尽力解释。我对性能不太了解,但我相信你还需要考虑一个视图构造,它大约需要80%的时间
np。所有的
都需要。我无法在你提到的更高维度上重现2倍或6倍的性能改进。创建视图应该是O(1)如果数组已经是连续的;它们应该是连续的。也许它没有创建视图,但似乎有一些东西不是O(1).我在这里做得不对吗?@ayhan我不得不给你我的投票结果…对于非常大的数组,你的方法比这个方法快。对于中间数组,它们非常接近。RegardsThanks。我想可能是随机数产生了最坏的情况。顺便说一句,我从你的方法中学到了很多。很高兴认识Eelco(+1),它是在NumPy中出现的吗?我本来打算用它来制作一个NumPy EP;但是向后兼容性会有点差,我决定在NumPy发布周期允许的时间之前就想要这个功能。但是,是的,我认为如果这个包中的功能能够进入NumPy,这会很有意义。
import numpy_indexed as npi
test = [[[0, 3], [3, 0]]]
# check which elements of arr are present in test (checked along axis=0 by default)
flags = npi.contains(test, arr)
# if you want the indexes:
idx = np.flatnonzero(flags)