【问题标题】:Set 2D array elements based on 2D index array根据二维索引数组设置二维数组元素
【发布时间】:2020-03-09 04:50:05
【问题描述】:

在 Python 中,假设您有一个形状为零的二维数组 (N,4,4):

z = array([[[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]],

   [[0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.],
    [0., 0., 0., 0.]]])

你有一个二维索引数组:

i = array([[1, 1, 1, 1],
       [1, 0, 0, 0],
       [0, 0, 1, 1],
       [1, 1, 1, 0]])

还有一些有价值的二维数组:

v = array([[ 2.,  4., 10.,  7.],
   [10.,  9.,  9.,  2.],
   [ 3.,  8.,  8.,  8.],
   [ 8.,  6., 10.,  1.]])

有没有办法在不使用循环的情况下用v 的值填充z 的元素,但在i 表示的切片中?

注意:有没有办法以可扩展的方式执行此操作,这样如果您有一个 N 通道数组 z,其中 N>>1,则在填充值时不需要直接索引 z[i]来自v?

为清楚起见,生成的 z 数组如下所示:

z = array([[[0., 0., 0., 0.],
    [0., 9., 9., 2.],
    [3., 8., 0., 0.],
    [0., 0., 0., 1.]],

   [[2., 4., 10., 7.],
    [10., 0., 0., 0.],
    [0., 0., 8., 8.],
    [8, 6., 10., 0.]]])

显然,使用类似的东西:

z = v[i,:,:]

永远不会工作,但也许有办法使用rows, cols 来做到这一点?

非常感谢!


编辑:

为了清楚起见,这里有一个类似的示例,但对于 cmets 中要求的 3D z:

z = array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],

       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])


i = array([[2, 1, 2, 1],
       [1, 1, 2, 1],
       [1, 1, 1, 1],
       [1, 0, 0, 1]])


v = array([[5., 5., 0., 4.],
       [4., 6., 8., 3.],
       [4., 0., 4., 8.],
       [7., 6., 5., 7.]])

z 会变成:

z = array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 6., 5., 0.]],

       [[0., 5., 0., 4.],
        [4., 6., 0., 3.],
        [4., 0., 4., 8.],
        [7., 0., 0., 7.]],

       [[5., 0., 0., 0.],
        [0., 0., 8., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])

【问题讨论】:

    标签: python multidimensional-array indexing element


    【解决方案1】:

    你总是可以使用掩码和乘法:

    from numpy import array
    z = array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]],
    
       [[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])
    i = array([[1, 1, 1, 1],
           [1, 0, 0, 0],
           [0, 0, 1, 1],
           [1, 1, 1, 0]])
    v = array([[ 2.,  4., 10.,  7.],
       [10.,  9.,  9.,  2.],
       [ 3.,  8.,  8.,  8.],
       [ 8.,  6., 10.,  1.]])
    z[0] = ~i.astype(bool)*v
    z[1] = i.astype(bool)*v
    

    输出:

    z = 
    array([[[ 0.,  0.,  0.,  0.],
            [ 0.,  9.,  9.,  2.],
            [ 3.,  8.,  0.,  0.],
            [ 0.,  0.,  0.,  1.]],
    
           [[ 2.,  4., 10.,  7.],
            [10.,  0.,  0.,  0.],
            [ 0.,  0.,  8.,  8.],
            [ 8.,  6., 10.,  0.]]])
    

    对于更一般的情况:

    for ax in np.unique(i):
        mask = i == ax
        z[ax] = mask*v
    print(z)
    

    输出:

    [[[0. 0. 0. 0.]
      [0. 0. 0. 0.]
      [0. 0. 0. 0.]
      [0. 6. 5. 0.]]
    
     [[0. 5. 0. 4.]
      [4. 6. 0. 3.]
      [4. 0. 4. 8.]
      [7. 0. 0. 7.]]
    
     [[5. 0. 0. 0.]
      [0. 0. 8. 0.]
      [0. 0. 0. 0.]
      [0. 0. 0. 0.]]]
    

    注意:这里我假设i 中的值与z 中的频道相同。如果不同,可以尝试使用 np.unique 代替:

    for i_val,ax in zip(np.unique(i),range(z.shape[0]))::
        mask = i == i_val
        z[ax] = mask*v
    

    编辑

    单行是:

    >>> z = np.array([*map(i.__eq__,np.unique(i))])*np.array([v]*z.shape[0])
    >>> z
    array([[[0., 0., 0., 0.],
            [0., 0., 0., 0.],
            [0., 0., 0., 0.],
            [0., 6., 5., 0.]],
    
           [[0., 5., 0., 4.],
            [4., 6., 0., 3.],
            [4., 0., 4., 8.],
            [7., 0., 0., 7.]],
    
           [[5., 0., 0., 0.],
            [0., 0., 8., 0.],
            [0., 0., 0., 0.],
            [0., 0., 0., 0.]]])
    

    【讨论】:

    • 感谢您的回复,不幸的是,这对于具有许多频道的z 的高维版本是不可扩展的。这是我的错,因为他的问题不够清楚,所以我已经相应地更新了文本。
    • 您能否提供一个示例,说明您对 3 个频道的 z 的要求?
    • 谢谢!我试过了,一切看起来都很好:D
    • 很高兴为您提供帮助:)
    • 如果4D数组是X那么for k in range(X.shape[0]):X[k] = np.array([*map(i.__eq__,np.unique(i))])*np.array([v]*X[k].shape[0])
    【解决方案2】:

    没有 numpy 会更复杂:

    r = list(zip(i,v))
    z[0] = [[l2[i] if l1[i]==0 else 0 for i in range(4)] for l1, l2 in r ]
    z[1] = [[l2[i] if l1[i]==1 else 0 for i in range(4)] for l1, l2 in r ]
    

    【讨论】:

    • 谢谢,这可行,但不幸的是有循环......所以不是理想的情况,但如果没有循环就无法完成,那么它是目前最好的选择。
    • @user8188120 它对于 z[0]、z[1]... 等的 每个 都有一个嵌套循环。绝对是 不是 b> 比 numpy 解决方案更好,这些解决方案对于 z[0]、z[1]... 等中的每一个都没有单个循环。
    【解决方案3】:

    可以使用numpy.where:

    z[0] = np.where(i, z[0], v)
    z[1] = np.where(1 - i, z[1], v)
    

    输出:

    array([[[ 0.,  0.,  0.,  0.],
            [ 0.,  9.,  9.,  2.],
            [ 3.,  8.,  0.,  0.],
            [ 0.,  0.,  0.,  1.]],
    
           [[ 2.,  4., 10.,  7.],
            [10.,  0.,  0.,  0.],
            [ 0.,  0.,  8.,  8.],
            [ 8.,  6., 10.,  0.]]])
    

    并且在您更新之后,如果 i 持有要更改的 z 的索引(与您示例中的 0 和 1 相反),它可以轻松缩放为:

    for N in range(z.shape[0]):    
        z[N] = np.where(i == N, v, z[N])
    

    或者如果你真的想避免所有循环:

    z = np.where(i == (np.where(np.ones(len(z.reshape(-1))) == 1)[0] // (z.shape[1] * z.shape[2])).reshape(z.shape), v, z)
    

    输出:

    array([[[0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.],
        [0., 6., 5., 0.]],
    
       [[0., 5., 0., 4.],
        [4., 6., 0., 3.],
        [4., 0., 4., 8.],
        [7., 0., 0., 7.]],
    
       [[5., 0., 0., 0.],
        [0., 0., 8., 0.],
        [0., 0., 0., 0.],
        [0., 0., 0., 0.]]])
    

    【讨论】:

    • 感谢您的回复,不幸的是,这对于具有许多通道的z 的高维版本无法扩展,因为在真正的问题中我将无法索引z[i] 如果有据说有数百个频道。这是我的错,因为他的问题不够清楚,所以我已经相应地更新了文本。
    猜你喜欢
    • 2022-11-19
    • 1970-01-01
    • 2023-03-07
    • 2018-06-25
    • 2020-07-30
    • 2021-02-03
    • 2012-04-10
    • 1970-01-01
    • 2011-07-07
    相关资源
    最近更新 更多