【问题标题】:NumPy: 2-D array tiled, converted to a 1-D array, and have to become a 2-D array againNumPy:2-D 数组平铺,转换为 1-D 数组,并且必须再次变为 2-D 数组
【发布时间】:2022-06-11 01:16:33
【问题描述】:

好吧,我不是 numpy 方面的专家,如果答案很明显,很抱歉,但这已经困扰我好几天了,所以我除了在这里问之外别无选择。所以,这是我的输入数组:

a = np.array([
    [0, 0, 1, 3, 4,  5,  12, 0, 0,  0, 0,  0  ],
    [0, 0, 4, 0, 13, 0,  0,  2, 0,  0, 0,  0  ],
    [1, 2, 3, 4, 5,  6,  7,  8, 0,  0, 0,  0  ],
    [5, 4, 9, 0, 3,  0,  7,  2, 0,  0, 0,  0  ],
    [0, 0, 0, 0, 0,  0,  0,  0, 0,  0, 0,  0  ],
    [0, 0, 0, 0, 1,  0,  5,  7, 5,  0, 1,  0  ],
    [0, 0, 0, 0, 0,  5,  12, 3, 0,  4, 12, 3  ],
    [0, 0, 0, 0, 5,  14, 0,  9, 10, 2, 0,  15 ]
])

需要将其拆分为 4x4 大小的图块(这意味着每个图块有 16 个元素,您会明白为什么这很重要)。 我将其平铺(使用 Iosif Doundoulakis 的 np.reshape() 方法,解释为 here,大喊大叫):

def tiling(arr):
    # 16 - total number of elements getting into a tile
    # 4 - width of a tile
    # 4 - height of a tile
    b = arr.reshape(arr.shape[0] // 4, 4, arr.shape[1] // 4, 4, 1)
    return b.swapaxes(1, 2)

...当我打电话给tiles = tiling(a) 时,我得到了类似的结果:

*为了便于阅读,我对输出进行了格式化,实际输出看起来不同,但组织方式相同。

[[
 [
  [[ 0] [ 0] [ 1] [ 3]]
  [[ 0] [ 0] [ 4] [ 0]]
  [[ 1] [ 2] [ 3] [ 4]]
  [[ 5] [ 4] [ 9] [ 0]]
 ]
.... this is one tile, there are 5 more ...
]]

这正是我希望我的瓷砖看起来的样子。然后,我将平铺数组展平,所以它变成了

[ 0  0  1  3  0  0  4  0  1  2  3  4  5  4  9  0  4  5 12  0 13  0  0  2
  5  6  7  8  3  0  7  2  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  1  0  5  7
  0  5 12  3  5 14  0  9  0  0  0  0  5  0  1  0  0  4 12  3 10  2  0 15]

每 16 个数字代表一个图块。下一步是将展平数组传递给一个外部程序,该程序返回一个具有相同形状的数组 - 一维数组。目前,数据仅传递给外部实用程序并由其返回,因此数组保留其值。

知道进入 tile (16) 的数组元素的总数,以及 tile 的形状 (4, 4),我如何将这个 1-D 数组重新转换为 tile,然后创建一个 2 -D 来自这些图块的数组,看起来像从一开始的那个?

编辑: 我出去几天了,抱歉耽搁了! 问题是我有一个平坦的一维数组,因为我想重塑为一个形式的外部实用程序,我从原始数组中得到,所以类似于:

    arr (with a shape (8, 12, 1))
        |
        |  tile the array (using Iosif 
        |  Doundoulakis's method)
        V 
    tiled_arr = arr.reshape(2, 3, 4, 4, 1)
        |
        | flatten the tiled array
        V 
    tiled_arr.flatten('C')
        |
        | pass to the external utility
        V 
    it returns the same flat array, for now, but it wouldn't in the nearest future, so reformatting tiled_array is not an option
        |
        | pass it to a reshaping function in question
        V 
    It should reshape the flat array back into (8, 12, 1), which is the shape of the original array arr

我昨天想出了这个代码:

def reshape(flat_array, original_array):

    a = np.array([np.split(flat_array, 16)]).reshape(original_array.shape[1] // 4, 4, original_array.shape[0] // 4, 4, original_array.shape[2])

    b = a.reshape(2, 3, 4, 4)
    return b.swapaxes(1, 2).reshape(original_array.shape)

...它有效,我得到了我想要的结果。但在我看来,它至少可以优化一点。

【问题讨论】:

  • 我无法运行您的 tiling 函数。除了没有定义frame,它还引发了ValueError: cannot reshape array of size 96 into shape (0,16,3,4,1)
  • 我修好了,现在应该没问题了。由于复制代码和硬编码一些变量值,我把函数弄乱了,但现在已经修复了,再试一次。感谢您指出这一点,而不是让它沉入其中:)

标签: python arrays numpy reshape np


【解决方案1】:

我认为这实际上就像另一个swapaxesreshape 一样简单。首先,您需要调用swapaxes(1, 2) 再次 以撤消上一次调用。然后将其重新整形为 a 的形状。

>>> tiles
array([[[[[ 0],
          [ 0],
          [ 1],
          [ 3]],

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

>>> tiles.swapaxes(1, 2).reshape(a.shape)
array([[ 0,  0,  1,  3,  4,  5, 12,  0,  0,  0,  0,  0],
       [ 0,  0,  4,  0, 13,  0,  0,  2,  0,  0,  0,  0],
       [ 1,  2,  3,  4,  5,  6,  7,  8,  0,  0,  0,  0],
       [ 5,  4,  9,  0,  3,  0,  7,  2,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  1,  0,  5,  7,  5,  0,  1,  0],
       [ 0,  0,  0,  0,  0,  5, 12,  3,  0,  4, 12,  3],
       [ 0,  0,  0,  0,  5, 14,  0,  9, 10,  2,  0, 15]])

如果你没有a.shape,你可以用(S[0]*S[2], S[1]*S[3])之类的东西来计算它,其中Stiles.shape

tiles.swapaxes(1, 2).reshape(x.shape[0] * x.shape[2], x.shape[1] * x.shape[3])

【讨论】:

    【解决方案2】:

    Iosif Doundoulakis 方法的一个好处是平铺数组和原始数组共享内存。

    original_array = np.array([
        [0, 0, 1, 3, 4, 5, 12, 0, 0, 0, 0, 0],
        [0, 0, 4, 0, 13, 0, 0, 2, 0, 0, 0, 0],
        [1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0],
        [5, 4, 9, 0, 3, 0, 7, 2, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 5, 7, 5, 0, 1, 0],
        [0, 0, 0, 0, 0, 5, 12, 3, 0, 4, 12, 3],
        [0, 0, 0, 0, 5, 14, 0, 9, 10, 2, 0, 15],
    ])
    
    tile_rows, tile_cols = tile_shape = (2, 4)
    
    grid_rows, grid_cols = grid_shape = (original_array.shape[0] // tile_shape[0],
                                         original_array.shape[1] // tile_shape[1])
    
    tiled_array = original_array \
        .reshape((grid_rows, tile_rows, grid_cols, tile_cols, 1)) \
        .swapaxes(1, 2)
    
    print(np.shares_memory(tiled_array, original_array))  # True
    

    tiled_arrayoriginal_array 的视图;对tiled_array 的任何就地修改也适用于original_array

    tiled_array[0, 0] = 99
    print(original_array)
    

    打印

    [[99 99 99 99  4  5 12  0  0  0  0  0]
     [99 99 99 99 13  0  0  2  0  0  0  0]
     [ 1  2  3  4  5  6  7  8  0  0  0  0]
     [ 5  4  9  0  3  0  7  2  0  0  0  0]
     [ 0  0  0  0  0  0  0  0  0  0  0  0]
     [ 0  0  0  0  1  0  5  7  5  0  1  0]
     [ 0  0  0  0  0  5 12  3  0  4 12  3]
     [ 0  0  0  0  5 14  0  9 10  2  0 15]]
    

    正如其他人所指出的,可以通过将轴交换回来并重新整形来反转转换,

    recovered_original_array = tiled_array \
        .swapaxes(1, 2) \
        .reshape((grid_rows * tile_rows, grid_cols * tile_cols))
    
    print(np.all(recovered_original_array == original_array))  # True
    

    三个数组都共享内存。

    print(np.shares_memory(recovered_original_array, original_array)) # True
    

    但是,当您使用flatten 方法展平数组时,这个有用的属性会被破坏,因为flatten 总是返回副本而不是视图,

    flat_array = tiled_array.flatten()
    print(np.shares_memory(flat_array, original_array))  # False
    

    reshape 方法以-1 作为其参数调用,如果可能,将返回一个平面视图,否则将返回一个副本。在这种情况下,它返回一个副本。

    flat_array = tiled_array.reshape(-1)
    print(np.shares_memory(flat_array, original_array))  # False
    

    无论哪种方式,您都可以轻松地从flat_array 恢复tiled_array

    recovered_tiled_array = flat_array.reshape((grid_rows, grid_cols, tile_rows, tile_cols, 1))
    print(np.shares_memory(recovered_tiled_array, tiled_array))  # False
    print(np.all(recovered_tiled_array == tiled_array))  # True
    

    据我所知,没有办法按照您需要的顺序制作原始阵列的平面阵列视图。但是,您可以制作平铺阵列的平面视图,然后进行处理。 为此,请复制 tiled_array

    tiled_array = original_array \
        .reshape((grid_rows, tile_rows, grid_cols, tile_cols, 1)) \
        .swapaxes(1, 2).copy()
    
    print(np.shares_memory(tiled_array, original_array))  # False
    

    允许相同的平面视图

    flat_array = tiled_array.reshape(-1)
    
    print(np.shares_memory(flat_array, tiled_array))  # True
    
    flat_array[:] = function_on_flat_array(flat_array)  # changes apply automatically to flat_array
    

    【讨论】:

      【解决方案3】:

      我不明白你到底想要什么,但我猜你正在搜索类似 my previous answer 的东西(以你的例子得到 shape = (6, 4 ,4)):

      a.reshape(a.shape[0] // 4, 4, -1, 4).swapaxes(1, 2).reshape(a.size // (4 * 4), 4, 4)
      

      您需要将返回数组重新整形为a.size // (4 * 4), 4, 4)(如果您确定可以被4或16整除的形状......),因此平铺函数必须更改为:

      def tiling(arr):
          b = arr.reshape(arr.shape[0] // 4, 4, arr.shape[1] // 4, 4, 1)
          return b.swapaxes(1, 2).reshape(arr.size // (4 * 4), 4, 4)
      
      # [[[ 0  0  1  3]
      #   [ 0  0  4  0]
      #   [ 1  2  3  4]
      #   [ 5  4  9  0]]
      # 
      #  [[ 4  5 12  0]
      #   [13  0  0  2]
      #   [ 5  6  7  8]
      #   [ 3  0  7  2]]
      # 
      #  [[ 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]
      #   [ 1  0  5  7]
      #   [ 0  5 12  3]
      #   [ 5 14  0  9]]
      # 
      #  [[ 0  0  0  0]
      #   [ 5  0  1  0]
      #   [ 0  4 12  3]
      #   [10  2  0 15]]]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-19
        • 1970-01-01
        • 2022-10-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多