【问题标题】:Reshaping 2d NumPy array into 3d with recurring rows将 2d NumPy 数组重塑为具有重复行的 3d
【发布时间】:2019-06-26 12:25:48
【问题描述】:

我有一个如下的 NumPy 数组:

arr = np.array([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]])

我希望这样安排:

[[[6,7,8,9,10],
  [1,2,3,4,5]],
 [[11,12,13,14,15],
  [6,7,8,9,10]],
 [[16,17,18,19,20],
  [11,12,13,14,15]]]

所以本质上是一个 3D 数组,数组的每一行都有 2x5。 我试过的代码是:

x=np.zeros([3,2,5])
for i in range(len(arr)):
    x[i]=arr[i:i+2,:][::-1]

但这会导致以下输出:

[[[ 6.  7.  8.  9. 10.]
  [ 1.  2.  3.  4.  5.]]    
 [[ 0.  0.  0.  0.  0.]
  [ 0.  0.  0.  0.  0.]]  
 [[ 0.  0.  0.  0.  0.]
  [ 0.  0.  0.  0.  0.]]]

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

[[[ 6.  7.  8.  9. 10.]
  [ 1.  2.  3.  4.  5.]]    
 [[11. 12. 13. 14. 15.]
  [ 6.  7.  8.  9. 10.]]    
 [[16. 17. 18. 19. 20.]
  [11. 12. 13. 14. 15.]]]

【问题讨论】:

  • 当我尝试执行您的代码尝试时,我得到了一个错误,正如我所期望的那样。如果我将循环的range 更改为range(x.shape[0])(即range(len(x))),我会得到你想要的结果。您确定您粘贴的数组来自上述输入和代码吗?

标签: python arrays numpy reshape


【解决方案1】:

我们可以利用基于np.lib.stride_tricks.as_stridedscikit-image's view_as_windows 来获得滑动窗口。 More info on use of as_strided based view_as_windows.

from skimage.util.shape import view_as_windows

x = view_as_windows(arr,(2,arr.shape[1]))[:,0,::-1]

这只是输入数组的一个视图。因此,没有额外的内存开销和几乎免费的运行时间。如果你想要一个拥有自己内存空间的输出,请在此处附加.copy(),即x.copy()

示例运行 -

In [15]: from skimage.util.shape import view_as_windows

In [16]: view_as_windows(arr,(2,arr.shape[1]))[:,0,::-1]
Out[16]: 
array([[[ 6,  7,  8,  9, 10],
        [ 1,  2,  3,  4,  5]],

       [[11, 12, 13, 14, 15],
        [ 6,  7,  8,  9, 10]],

       [[16, 17, 18, 19, 20],
        [11, 12, 13, 14, 15]]])

【讨论】:

    【解决方案2】:

    您可以使用一些stride tricks 将您的数组构建为输入数组上的多维滑动窗口:

    import numpy as np 
    arr = np.array([[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15],[16,17,18,19,20]]) 
    
    # compute the strides and shape of the output array
    in_strides = arr.strides 
    out_strides = in_strides[:1] + in_strides 
    out_shape = (3, 2) + arr.shape[-1:]  # keep the last dimension's size
    strided = np.lib.stride_tricks.as_strided(arr, strides=out_strides, shape=out_shape)
    out_arr = strided[:, ::-1, :].copy()  # use a copy to stay safe
    

    只要out_shape[-1] <= arr.shape[1]sum(out_shape[:2]) <= arr.shape[0] + 1,以上内容就可以安全运行。这些是使滑动窗口在原始数组中有意义的约束,您的实际用例自然应该尊重这些。

    重要提示:

    • 如果上述不等式不成立,那么滑动窗口将愉快地滑出数组的内存范围,您将默默地开始看到垃圾矩阵元素:

      >>> out_strides = in_strides[:1] + in_strides 
      ... out_shape = (3, 3, 5)  # 3 + 3 == 6 > arr.shape[0] + 1 == 5
      ... np.lib.stride_tricks.as_strided(arr, strides=out_strides, shape=out_shape)
      array([[[         1,              2,              3,              4,
                        5],
          [             6,              7,              8,              9,
                       10],
          [            11,             12,             13,             14,
                       15]],
      
         [[             6,              7,              8,              9,
                       10],
          [            11,             12,             13,             14,
                       15],
          [            16,             17,             18,             19,
                       20]],
      
         [[            11,             12,             13,             14,
                       15],
          [            16,             17,             18,             19,
                       20],
          [           384,            193, 94379169559968,              0,
                        0]]])
      
    • 如果您之后不改变您的数组,并且只有这样,您可以省略上面最后的.copy() 调用。这将为您提供一个与原始数组共享内存的跨步数组,但更重要的是,数组的行将彼此共享内存。这不是你通常想要的,但是如果你的真实数组非常大并且你知道你可以安全地假设这些值不会被独立改变,内存占用可能很重要。要考虑的另一个方面是,在结果上调用 .copy() 会给你一个连续的内存块,这可能会更好地提高性能,具体取决于你计划对结果数组做什么。

    【讨论】:

      【解决方案3】:

      无需使用任何循环。切片就足够了:

      x = np.zeros([3,2,5], dtype=int)
      x[:,0] = arr[-3:,:]
      x[:,1] = arr[:3,:]
      

      基本上,您将所有页面中的第 0 行分配给 arr 的最后 3 行,将所有页面中的第 1 行分配给 arr 的前 3 行。

      【讨论】:

        猜你喜欢
        • 2017-09-18
        • 1970-01-01
        • 2016-05-22
        • 2015-10-19
        • 2019-09-12
        • 1970-01-01
        • 2019-07-10
        • 2016-01-17
        • 2023-01-25
        相关资源
        最近更新 更多