【问题标题】:How do I replace values along z-axis in Numpy 3D array based on 2D index and 1D value vector如何根据 2D 索引和 1D 值向量替换 Numpy 3D 数组中沿 z 轴的值
【发布时间】:2017-08-10 02:43:58
【问题描述】:

我似乎很难理解数组索引。

给出了什么:

我确实有一个像这样的 3d 数组:

a_3d = np.zeros((3,3,3))

二维索引数组:

a_2d_index = np.array([[0,0,1], [0,0,0], [0,1,1]]).astype('bool')

将值放入 x,y 位置的 3d 数组中:

a_1d_fill = np.array([10,20,30])

现在,我确实想使用 a_2d_index 来查找 a_3d 中的位置,并将 a_1d_fill 垂直放置在这个 x,y 位置...

最终的结果应该是这样的:

a_3d := [[[0,0, 10],
          [0,0,  0],
          [0,10,10]],
         [[0,0, 20],
          [0,0,  0],
          [0,20,20]],
         [[0,0, 30],
          [0,0,  0],
          [0,30,30]]]

这将用于非常大的阵列,因此内存效率和速度至关重要......(少量复制,最好是就地修改)

【问题讨论】:

    标签: arrays numpy indexing


    【解决方案1】:

    也许一点解释和直觉可能会帮助未来的读者更好地理解切片。 我(无耻地)使用Stuart Berg's solution 向用户解释切片以获得直观的感觉。

    数组和掩码定义:

    In [57]: a_3d        # array with unique numbers for better understanding.
    Out[57]: 
    array([[[13, 14, 15],
            [23, 24, 25],
            [33, 34, 35]],
    
           [[ 3,  4,  5],
            [ 6,  7,  8],
            [ 9, 10, 11]],
    
           [[ 0,  1,  2],
            [30, 31, 32],
            [40, 41, 42]]], dtype=uint8)
    

    将上述 3D 数组理解为 3x3 数组的三个切片,最顶部的数组具有索引 0,中心一个具有索引 1,底部一个具有索引 2

    布尔掩码:

    In [58]: a_2d_index
    Out[58]: 
    array([[False, False,  True],
           [False, False, False],
           [False,  True,  True]], dtype=bool)
    

    现在,让我们使用布尔掩码 a_2d_index 对数组 a_3d 进行切片

    In [68]: a_3d[:, a_2d_index]   # : means apply the mask to all the slices(here 3)
    Out[68]: 
    array([[15, 34, 35],
           [ 5, 10, 11],
           [ 2, 41, 42]], dtype=uint8)
    

    好的,现在我们得到了上面的结果。为什么以及如何?所以,想象一下:我们获取布尔掩码数组,然后将数组 a_3d 叠加在它的每个切片上。

    现在,无论掩码中有布尔值True,数组a_3d 中的相应元素将(发光?)并为结果数组做出贡献。当我们将掩码放在每个切片上时,每个切片都会发生这种情况(因为我们使用了:,所以我们对数组a_3d 中的所有切片都这样做)。

    好了,切片完成了!现在,我们要分配新值(其中掩码具有布尔值 True)。

    分配新值:

    In [69]: a_1d_fill
    Out[69]: array([10, 20, 30])
    

    这是我们拥有的一维数组。但是,掩码是二维数组。因此,我们使用 np.newaxis 将其更改为 2D

    In [70]: a_2d_fill = a_1d_fill[:, np.newaxis]
    
    In [71]: a_2d_fill
    Out[71]: 
    array([[10],
           [20],
           [30]])
    
    
    In [73]: a_3d[:, a_2d_index] = a_2d_fill
    

    现在,此分配会将值 10 复制到布尔掩码具有 True 值的第一个切片中的索引,然后将值 20 复制到布尔掩码具有值 True 的第二个切片中的索引最后将值 30 复制到布尔掩码值为 True 的第三个切片中的索引。

    最后的结果是这样的:

    In [74]: a_3d
    Out[74]: 
    array([[[13, 14, 10],
            [23, 24, 25],
            [33, 10, 10]],
    
           [[ 3,  4, 20],
            [ 6,  7,  8],
            [ 9, 20, 20]],
    
           [[ 0,  1, 30],
            [30, 31, 32],
            [40, 30, 30]]], dtype=uint8)
    

    呸!那真的很长。因此,简而言之,结果数组在第一、第二和第三个切片中应分别具有值 102030(其中布尔掩码的值为 True)。


    P.S.:切片提供原始数组的 viewsreferences。因此,当我们使用切片更改值时,这将影响原始数组。因此,这是一个就地修改。

    【讨论】:

    • 感谢您的解释,这对您有帮助!
    【解决方案2】:
    In [26]: a_3d = np.zeros((3,3,3), dtype=int)
    
    In [27]: a_2d_index = np.array([[0,0,1], [0,0,0], [0,1,1]]).astype('bool')
    
    In [28]: a_1d_fill = np.array([10,20,30])
    
    In [29]: a_3d[:,a_2d_index] = a_1d_fill[:,np.newaxis]
    
    In [30]: a_3d
    Out[30]:
    array([[[ 0,  0, 10],
            [ 0,  0,  0],
            [ 0, 10, 10]],
    
           [[ 0,  0, 20],
            [ 0,  0,  0],
            [ 0, 20, 20]],
    
           [[ 0,  0, 30],
            [ 0,  0,  0],
            [ 0, 30, 30]]])
    

    【讨论】:

    • 谢谢,看起来很干净!一个问题。如果我有一个 4d 数组并且我想应用于 4D 数组的一个切片(形状为 (10,3,3,3)),这不起作用。假设我想在索引为 2 的切片上执行此操作:a_4d_array[ 2, :, a_2d_index] = a_1d_fill[:, np.newaxis] 在我的脚本中失败,形状不匹配
    • 我承认我也很困惑为什么这两行不相等。我希望他们做同样的事情,但发现他们没有。
    • a_4d_array[2, :, idx] 是(棘手的)混合基本和高级索引的情况,docs.scipy.org/doc/numpy/reference/…。它的形状是您可能期望的转置,首先是 idx 形状,最后是切片形状。
    猜你喜欢
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 2021-07-04
    • 1970-01-01
    • 2016-03-23
    • 2012-01-29
    • 2018-06-01
    • 2019-06-25
    相关资源
    最近更新 更多