重塑2D NumPy的数组转换成3D使用周期性排

问题描述 投票:3回答:3

我有一个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阵列与阵列的每一行中2×5。我试过的代码是:

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.]]]
python arrays numpy reshape
3个回答
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]]])

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()的结果会给你一个连续的内存块,这可能是获得更好的性能的路线,这取决于你打算用所得阵列做什么。

0
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.