簡體   English   中英

使用重復行將2d NumPy數組重新整形為3d

[英]Reshaping 2d NumPy array into 3d with recurring rows

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

您可以使用一些步幅技巧將數組構造為輸入數組上的多維滑動窗口:

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()將為您提供一個連續的內存塊,這可能會更好地實現性能,具體取決於您計划對結果數組執行的操作。

我們可以利用基於np.lib.stride_tricks.as_strided scikit-image's view_as_windows來獲得滑動窗口。 有關使用基於view_as_windowsas_strided的更多信息

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]]])

無需使用任何循環。 切片就足夠了:

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

基本上你在所有頁面的最后3行的第0行分配arr ,並在所有頁第1行至第3行的arr

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM