代码之家  ›  专栏  ›  技术社区  ›  LMC

Numpy数组布尔索引以获取包含元素

  •  1
  • LMC  · 技术社区  · 2 月前

    给定一个(3,2,2)数组,在给定第三维上的单个值的情况下,如何获得第二维元素

    import numpy as np
    
    
    arr = np.array([
     [[31.,  1.], [41.,  1.]],
     [[63.,  1.],[73.,  3.]],
     [[ 95.,   1.], [100., 1]]
     ]
    )
    
    ref = arr[(arr[:,:,0] > 41.) & (arr[:,:,0] <= 63)]
    print(ref)
    

    结果

    [[63.  1.]]
    

    预期结果

    [[63.,  1.],[73.,  3.]]
    

    输入值是63,所以我不知道73是否存在,但我也想返回它。换句话说,如果值存在,则返回整个父数组而不进行整形。

    另一个例子

    ref = arr[(arr[:,:,0] <= 63)]

    退换商品

    [[31.  1.]
     [41.  1.]
     [63.  1.]]
    

    但应该回来

    [[[31.  1.]
     [41.  1.]]
     [[63.  1.]
     [73.  1.]]]
    
    2 回复  |  直到 2 月前
        1
  •  2
  •   chrslg    2 月前

    我想你想要

    arr[((arr[:,:,0]>41)&(arr[:,:,0]<=63)).any(axis=1)]
    

    arr[(arr[:,:,0] <= 63).any(axis=1)]
    

    一些解释。 首先,3D阵列也是1D阵列的2D阵列,或2D阵列的1D阵列。

    因此,如果预期的答案是一个“整父”数组,即一个2D数组数组(即一个3D数组,其中只有一些子数组),那么你需要一个1D布尔数组作为索引。例如 [True, False, False] 仅选择第一行, [[[31., 1.], [41., 1.]]] ,这与 arr[[0]] .

    arr[:,:,0]>41 是布尔值的2D数组。因此,将单独选取一些对(即沿第一个两个轴选择元素)。 例如 arr[[[True, False], [False, False], [False, False]]] 仅选择第一子阵列的第一对, [[31,1]] 有点像 arr[[0],[0]] 会做的。

    所以,既然你想要这样的东西 [[[31., 1.], [41., 1.]]] ,不是这样的 [[31,1]] ,我们需要生成一个1D布尔值数组,告诉每一行(沿轴0的每个子数组)我们是否需要它。

    现在,评论是关于如何决定我们是否想要一个子阵列。

    如果我们从 ref=arr[:,:,0]<=63
    这是ref=

    array([[ True,  True],
           [ True, False],
           [False, False]])
    

    得到 arr[ref] 会选择3对,这不是你想要的(同样,我们不希望使用二维布尔值数组作为选择器,因为我们想要完整的父对象)。

    你的尝试答案是使用 ref[:,0] ,这是一个由3个布尔值组成的1D数组(每行的第一个): [True, True, False] ,这将选择前3行。

    这个答案,就是使用 参考[:,0] ,它也是一个由3个布尔值组成的1D数组,每个True都表示至少行中有一个布尔值为True。所以,也 [正确、正确、错误]

    我们两个答案之间的差异在评论中使用的另一个例子中显示出来。

    ref=arr[:,:,0]>97
    
    array([[False, False],
           [False, False],
           [False,  True]])
    

    如果我们使用 参考[:,0] ,即 [False, False, False] ,则答案为空数组。即使最后一行的值超过97,也不会被选中。但我们只感兴趣(如果我们说 参考[:,0] )在第1对的第1个值>97

    如果我们使用 ref.any(axis=1) 正如在这个答案中 [False, False, True] ,我们排在最后一排。因为这意味着我们对至少一对具有第一值>的任何行感兴趣;97.

    我们还可以选择只有第二对具有第一值>97 ( arr[ref[:,1]] ). 或者其中一对(但不是两对)具有第一个值>97 ( arr[ref[:,0]^ref[:,1]] ). 等等。一切皆有可能。重点是,如果我们想得到一个整行(沿轴0的子数组)的列表,那么我们需要构建一个由3个布尔值组成的1D数组,为每一行决定我们是想要全部(True)还是什么都不想要(false)

        2
  •  2
  •   Suramuthu R    2 月前

    当使用条件直接像 condition = (arr[:,:,0] > 41.) & (arr[:,:,0] <= 63) ,它将输出平面化为一维数组。平坦的输出将是 [False, False, True, True, False, False] 在这种情况下。在平坦的输出中,我们失去了二维结构。

    相反,我们应该使用 mask 用于过滤。

    import numpy as np
    
    arr = np.array([
        [[31.,  1.], [41.,  1.]],
        [[63.,  1.], [73.,  3.]],
        [[95.,  1.], [100., 1.]]
    ])
    
    mask = (arr[:, :, 0] > 41.) & (arr[:, :, 0] <= 63)
    
    ref = arr[mask.any(axis=1)]
    print(ref)
    

    输出:

    [[[63.  1.]
     [73.  3.]]]
    
        3
  •  0
  •   LMC    2 月前

    终于找到了。布尔索引需要应用于正确的维度。
    为清楚起见,将索引分配给var

    ref = (arr[:,:,0] > 41) & (arr[:,:,0] <= 63)
    print(ref)
    print(arr[ref[:,0]])
    

    结果

    [[False False]
     [ True False]
     [False False]]
    [[[63.  1.]
      [73.  3.]]]
    

    更新: 正如公认的答案中提到的那样 .any(axis=1) 是正确的选择吗 就我而言,因为这个测试也应该匹配

    ref = (arr[:,:,0] > 97).any(axis=1)
    print(arr[ref])
    

    结果

    [[[ 95.   1.]
      [100.   1.]]]