将具有重复行的2d NumPy数组转换为3d

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数组,每一行都有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))”),我会得到你想要的结果。你确定你粘贴的数组来自上面的输入和代码吗? - Andras Deak -- Слава Україні
3个回答

1
你可以使用一些步幅技巧来构建一个多维滑动窗口数组,覆盖输入数组:
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的情况下才能安全使用。这些限制条件使得滑动窗口在原始数组内具有意义,您的实际用例应自然遵守这些条件。
重要提示:
  • If the above inequalities don't hold then the sliding window will happily slide out of the memory range of your array, and you'll silently start seeing garbage matrix elements:

    >>> 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]]])
    
  • If you won't mutate your array afterward, and only then, you may omit the final .copy() call in the above. This will give you a strided array that shares memory with the original array, but what's more important, the rows of the array will share memory with one another. This is not what you usually want, but if your real array is very large and you know you can safely assume that the values won't be independently mutated, the memory footprint might matter. Another aspect to consider is that calling .copy() on the result will give you a contiguous block of memory, which is probably better for performance down the line, depending on what you're planning to do with the resulting array.

1
我们可以利用np.lib.stride_tricks.as_stridedscikit-image的view_as_windows来获取滑动窗口。有关使用基于as_stridedview_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]]])

0

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接