使用重复行将2d NumPy数组重塑为3d

时间:2019-02-01 22:05:36

标签: python arrays numpy reshape

我有一个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.]]]

3 个答案:

答案 0 :(得分:1)

您可以使用一些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()将为您提供连续的内存块,这可能会更好地提高线下的性能,具体取决于您打算对结果数组进行的处理。 li>

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:0)

我们可以利用基于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]]])