【问题标题】:Check if 2d array exists in 3d array in Python?检查Python中的3d数组中是否存在2d数组?
【发布时间】:2018-10-13 06:00:31
【问题描述】:

我有一个形状为(1000, 12, 30) 的 3d 数组,我有一个形状为(12, 30) 的 2d 数组的列表,我想要做的是检查这些 2d 数组是否存在于 3d 数组中。 Python中有一个简单的方法可以做到这一点吗?我尝试了关键字in,但它不起作用。

【问题讨论】:

  • 这里的解决方案应该适用于您的问题stackoverflow.com/questions/7100242/…。标记重复
  • 这些问题不一样。
  • 解决方案适用于本案例。相应调整滚动窗口
  • 不适用。重复的问题应标记为重复,它们不是相同的问题。我不明白你为什么要把它标记为重复。
  • 我已经收回了旗帜。

标签: python python-3.x pandas numpy


【解决方案1】:

numpy 有一个方法,你可以用np.all

a = np.random.rand(3, 1, 2)
b = a[1][0]
np.all(np.all(a == b, 1), 1)
Out[612]: array([False,  True, False])

来自 bnaecker 的解决方案

np.all(a == b, axis=(1, 2))

如果只想检查退出与否

np.any(np.all(a == b, axis=(1, 2)))

【讨论】:

  • 或者更好,np.all(a == b, axis=(1,2))
  • @Wen 我明白了!谢谢你。如果深度像我在问题中提到的那样为 30,我仍然不确定这将如何工作?
  • @TeodoricoLevoff 查看 NumPy 的 broadcasting rules。在这种情况下,b 将沿第一个维度广播(复制)以匹配a。然后axis 的参数np.all 沿最后两个维度减少,留下一个形状为(30,)True 在索引i 的布尔数组a[i] == b
  • @TeodoricoLevoff 另请注意,如果您处理浮点数,您可能需要使用np.allclose() 而不是np.all()
  • @bnaecker 我明白了。但我只想在 (1000, 12, 30) 中存在完整的 (12, 30) 数组时返回 True。我认为上面提到的解决方案会检查 30 个列表中的每个单个值并为每个值输出一个布尔值?
【解决方案2】:

麻木

给定

a = np.arange(12).reshape(3, 2, 2)
lst = [
    np.arange(4).reshape(2, 2),
    np.arange(4, 8).reshape(2, 2)
]

print(a, *lst, sep='\n{}\n'.format('-' * 20))

[[[ 0  1]
  [ 2  3]]

 [[ 4  5]
  [ 6  7]]

 [[ 8  9]
  [10 11]]]
--------------------
[[0 1]
 [2 3]]
--------------------
[[4 5]
 [6 7]]

请注意,lst 是根据 OP 的数组列表。我将在下面创建一个 3d 数组 b

使用广播。使用广播规则。我希望a 的尺寸为(1, 3, 2, 2)b(2, 1, 2, 2)

b = np.array(lst)
x, *y = b.shape
c = np.equal(
    a.reshape(1, *a.shape),
    np.array(lst).reshape(x, 1, *y)
)

我将使用all 生成一个(2, 3) 真值数组,并使用np.where 找出ab 子数组中的哪一个实际上是相等的。

i, j = np.where(c.all((-2, -1)))

这只是验证我们实现了我们所追求的目标。我们应该观察到,对于每对 ij 值,子数组实际上是相同的。

for t in zip(i, j):
    print(a[t[0]], b[t[1]], sep='\n\n')
    print('------')

[[0 1]
 [2 3]]

[[0 1]
 [2 3]]
------
[[4 5]
 [6 7]]

[[4 5]
 [6 7]]
------

in

但是,为了完成OP关于使用in的想法

a_ = a.tolist()
list(filter(lambda x: x.tolist() in a_, lst))

[array([[0, 1],
        [2, 3]]), array([[4, 5],
        [6, 7]])]

【讨论】:

    【解决方案3】:

    这是一种快速的方法(以前是 used by @DanielF 以及 as @jaime 和其他人,毫无疑问),它使用一种技巧来从短路中受益:view-cast template-sized blocks to dtype void 的单个元素。当比较两个这样的块时,numpy 在第一个差异后停止,产生巨大的速度优势。

    >>> def in_(data, template):
    ...     dv = data.reshape(data.shape[0], -1).view(f'V{data.dtype.itemsize*np.prod(data.shape[1:])}').ravel()
    ...     tv = template.ravel().view(f'V{template.dtype.itemsize*template.size}').reshape(())
    ...     return (dv==tv).any()
    

    例子:

    >>> a = np.random.randint(0, 100, (1000, 12, 30))
    >>> check = a[np.random.randint(0, 1000, (10,))]
    >>> check += np.random.random(check.shape) < 0.001    
    >>>
    >>> [in_(a, c) for c in check]
    [True, True, True, False, False, True, True, True, True, False]
    # compare to other method
    >>> (a==check[:, None]).all((-1,-2)).any(-1)
    array([ True,  True,  True, False, False,  True,  True,  True,  True,
           False])
    

    提供与“直接”numpy 方法相同的结果,但速度快近 20 倍:

    >>> from timeit import timeit
    >>> kwds = dict(globals=globals(), number=100)
    >>> 
    >>> timeit("(a==check[:, None]).all((-1,-2)).any(-1)", **kwds)
    0.4793281531892717
    >>> timeit("[in_(a, c) for c in check]", **kwds)
    0.026218891143798828
    

    【讨论】:

    • 我希望更擅长实际编码的人最终会改进我的旧 vview 代码。一旦你有了 void 视图,你不能只使用np.in1d 吗?
    • @DanielF 你是对的,那应该更快。你能给我一个指向你的帖子的指针,这样我就可以正确地相信你了吗?
    • @DanielF 奇怪,我尝试使用 in1d 或者更确切地说是新的 isin,但速度慢了 10 倍。不知道这里发生了什么。
    • 我已经给出了几次答案:herehere 最近。但最初的想法来自@jaime here
    猜你喜欢
    • 2016-12-23
    • 2015-08-21
    • 2019-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 2015-02-22
    相关资源
    最近更新 更多