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)