【问题标题】:Changing subarrays in 3D arrays using values of a 2D array using numpy使用 numpy 使用 2D 数组的值更改 3D 数组中的子数组
【发布时间】:2020-07-09 15:23:14
【问题描述】:

我正在编写代码,一个问题突然出现在我的脑海中。所以基本上我有一个形状为
(2, 5, 5) 的 3D numpy 数组和一个形状为 (2, 4) 的 2D numpy 数组(这只是一个示例,数组可以更大)。我需要的是用我的 2D 数组中的值替换 3D 数组(切片 [:, 2:, 2:] )子数组中 1 的值。我想过从 3D 数组中我想要更改的值(那些)中获取索引,然后在 2D 数组中使用 for 循环来迭代这些值,但我不确定它是否是有效的方法,而且我我得到一个错误。

import numpy as np

arr = np.array([[[0.,  1., 43., 25., 21.],
                 [0.,  0.,  0.,  0.,  0.],
                 [0., 43.,  0.,  1.,  0.], 
                 [0., 43.,  1.,  0.,  1.],
                 [0., 45.,  0.,  1.,  0.]],

                [[0.,  1., 38., 29., 46.],
                 [0.,  0.,  0.,  0.,  0.],
                 [0., 32.,  0.,  0.,  1.],
                 [0., 26.,  0.,  0.,  1.],
                 [0., 30.,  1.,  1.,  0.]]])

values = [[2, 3, 1, 4],
          [4, 1, 5, 9]]

indexes = np.argwhere(newarr[:, 2:, 2:] == 1) + [0, 2, 2]

# indexes = [[0 2 3]
#            [0 3 2]
#            [0 3 4]
#            [0 4 3]
#            [1 2 4]
#            [1 3 4]
#            [1 4 2]
#            [1 4 3]]

for i in values:
    arr[indexes] == i

#Error
#index 2 is out of bounds for axis 0 with size 2

我想要的输出应该是

newarr = [[[0.,  1., 43., 25., 21.],
           [0.,  0.,  0.,  0.,  0.],
           [0., 43.,  0.,  2.,  0.], 
           [0., 43.,  3.,  0.,  1.],
           [0., 45.,  0.,  4.,  0.]],

          [[0.,  1., 38., 29., 46.],            
           [0.,  0.,  0.,  0.,  0.],
           [0., 32.,  0.,  0.,  4.],
           [0., 26.,  0.,  0.,  1.],
           [0., 30.,  5.,  9.,  0.]]])

我认为只使用 numpy 应该更有效率,但我看不到如何做到这一点,所以任何帮助将不胜感激,谢谢!

【问题讨论】:

    标签: python arrays numpy multidimensional-array


    【解决方案1】:

    您可以对arr 进行切片并使用转换为bool 的实际二进制值来屏蔽数组并在有1s 的位置进行切片分配:

    a_view = arr[:,2:,2:]
    a_view[a_view.astype('bool')] = np.array(values).ravel()
    

    print(arr)
    array([[[ 0.,  1., 43., 25., 21.],
            [ 0.,  0.,  0.,  0.,  0.],
            [ 0., 43.,  0.,  2.,  0.],
            [ 0., 43.,  3.,  0.,  1.],
            [ 0., 45.,  0.,  4.,  0.]],
    
           [[ 0.,  1., 38., 29., 46.],
            [ 0.,  0.,  0.,  0.,  0.],
            [ 0., 32.,  0.,  0.,  4.],
            [ 0., 26.,  0.,  0.,  1.],
            [ 0., 30.,  5.,  9.,  0.]]])
    

    【讨论】:

      【解决方案2】:

      两个问题:

      • 使用np.where 代替argwhere;你不需要迭代
      • 结果索引应用于切片,而不是原始数组

      使用你的数组:

      In [133]: arr = np.array([[[0.,  1., 43., 25., 21.], 
           ...:                  [0.,  0.,  0.,  0.,  0.], 
                ...
           ...:                  [0., 26.,  0.,  0.,  1.], 
           ...:                  [0., 30.,  1.,  1.,  0.]]]) 
           ...:  
      

      切片:

      In [136]: subarr = arr[:,2:,2:]                                                                      
      

      其中切片值为 1:

      In [137]: np.nonzero(subarr==1)                                                                      
      Out[137]: 
      (array([0, 0, 0, 0, 1, 1, 1, 1]),
       array([0, 1, 1, 2, 0, 1, 2, 2]),
       array([1, 0, 2, 1, 2, 2, 0, 1]))
      

      这就像你的argwhere,除了作为数组的元组,而不是偏移量。

      In [138]: values = [[2, 3, 1, 4], 
           ...:           [4, 1, 5, 9]] 
           ...:                                     
      

      该元组可用于索引切片,用于获取和设置:

      In [139]: subarr[np.nonzero(subarr==1)]                                                              
      Out[139]: array([1., 1., 1., 1., 1., 1., 1., 1.])
      In [140]: subarr[np.nonzero(subarr==1)]=np.ravel(values)             
      

      由于subarr 是一个视图,因此在其中设置值也会在arr 中设置值。无需将索引转换为arr 框架。

      In [141]: arr                                                                                        
      Out[141]: 
      array([[[ 0.,  1., 43., 25., 21.],
              [ 0.,  0.,  0.,  0.,  0.],
              [ 0., 43.,  0.,  2.,  0.],
              [ 0., 43.,  3.,  0.,  1.],
              [ 0., 45.,  0.,  4.,  0.]],
      
             [[ 0.,  1., 38., 29., 46.],
              [ 0.,  0.,  0.,  0.,  0.],
              [ 0., 32.,  0.,  0.,  4.],
              [ 0., 26.,  0.,  0.,  1.],
              [ 0., 30.,  5.,  9.,  0.]]])
      

      布尔索引

      正如其他答案所述,我们可以选择带有布尔掩码的元素,而无需 nonzero 步骤(在幕后,如果不完全相同,索引是相似的)。

      In [144]: arr = np.array([[[0.,  1., 43., 25., 21.], 
           ...:                  [0.,  0.,  0.,  0.,  0.], 
          ...
           ...:                  [0., 30.,  1.,  1.,  0.]]]) 
           ...:                                                                                            
      In [145]: subarr = arr[:,2:,2:]                                                                      
      In [146]: subarr[subarr==1]                                                                          
      Out[146]: array([1., 1., 1., 1., 1., 1., 1., 1.])
      
      In [148]: subarr[subarr==1] = np.ravel(values)                                                       
      In [149]: arr                                                                                        
      Out[149]: 
      array([[[ 0.,  1., 43., 25., 21.],
              [ 0.,  0.,  0.,  0.,  0.],
              ....
              [ 0., 30.,  5.,  9.,  0.]]])
      

      接近你的尝试

      实际上,如果您在 indices 上进行迭代,您的迭代可能会奏效:

      for i,v in zip(idx,np.ravel(values)):
           arr[tuple(i)] == v
      

      从我的where 元组开始:

      In [159]: Out[137]                                                                                   
      Out[159]: 
      (array([0, 0, 0, 0, 1, 1, 1, 1]),
       array([0, 1, 1, 2, 0, 1, 2, 2]),
       array([1, 0, 2, 1, 2, 2, 0, 1]))
      In [160]:                                                                                            
      

      您的偏移量argwhere

      In [160]: idx = np.transpose(Out[137])+[0,2,2]                                                       
      In [161]: idx                                                                                        
      Out[161]: 
      array([[0, 2, 3],
             [0, 3, 2],
             [0, 3, 4],
             [0, 4, 3],
             [1, 2, 4],
             [1, 3, 4],
             [1, 4, 2],
             [1, 4, 3]])
      

      迭代地使用它来索引arr(注意tuple的使用):

      In [162]: [arr[tuple(i)] for i in idx]                                                               
      Out[162]: [2.0, 3.0, 1.0, 4.0, 4.0, 1.0, 5.0, 9.0]
      

      直接在values 上迭代不起作用,因为这会返回 2 个列表。它需要被压平/散开。

      In [163]: for v in values: print(v)                                                                  
      [2, 3, 1, 4]
      [4, 1, 5, 9]
      

      【讨论】:

      • 感谢您的长回答,我可以看到我做错了很多事情,谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 2021-01-29
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      相关资源
      最近更新 更多