簡體   English   中英

NumPy:2-D 數組平鋪,轉換為 1-D 數組,並且必須再次變為 2-D 數組

[英]NumPy: 2-D array tiled, converted to a 1-D array, and have to become a 2-D array again

好的,我不是 numpy 方面的專家,如果答案很明顯,很抱歉,但這已經困擾我好幾天了,所以除了在這里問之外我別無選擇。 所以,這是我的輸入數組:

a = np.array([
    [0, 0, 1, 3, 4,  5,  12, 0, 0,  0, 0,  0  ],
    [0, 0, 4, 0, 13, 0,  0,  2, 0,  0, 0,  0  ],
    [1, 2, 3, 4, 5,  6,  7,  8, 0,  0, 0,  0  ],
    [5, 4, 9, 0, 3,  0,  7,  2, 0,  0, 0,  0  ],
    [0, 0, 0, 0, 0,  0,  0,  0, 0,  0, 0,  0  ],
    [0, 0, 0, 0, 1,  0,  5,  7, 5,  0, 1,  0  ],
    [0, 0, 0, 0, 0,  5,  12, 3, 0,  4, 12, 3  ],
    [0, 0, 0, 0, 5,  14, 0,  9, 10, 2, 0,  15 ]
])

它需要被分成大小為 4x4 的圖塊(這意味着每個圖塊有 16 個元素,您會明白為什么這很重要)。 我把它平鋪(使用 Iosif Doundoulakis 的np.reshape()方法,解釋在這里,大喊):

def tiling(arr):
    # 16 - total number of elements getting into a tile
    # 4 - width of a tile
    # 4 - height of a tile
    b = arr.reshape(arr.shape[0] // 4, 4, arr.shape[1] // 4, 4, 1)
    return b.swapaxes(1, 2)

...並且,當我調用tiles = tiling(a)時,我得到了類似的結果:

*為了便於閱讀,我對輸出進行了格式化,實際輸出看起來不同,但組織方式相同。

[[
 [
  [[ 0] [ 0] [ 1] [ 3]]
  [[ 0] [ 0] [ 4] [ 0]]
  [[ 1] [ 2] [ 3] [ 4]]
  [[ 5] [ 4] [ 9] [ 0]]
 ]
.... this is one tile, there are 5 more ...
]]

這正是我希望我的瓷磚看起來的樣子。 然后,我將平鋪陣列展平,所以它變成

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

每16個數字代表一個瓷磚。 下一步是將展平數組傳遞給一個外部程序,該程序返回一個具有相同形狀的數組 - 一維數組。 目前,數據只傳遞給外部實用程序並由它返回,因此數組保留它的值。

知道進入瓦片的數組元素總數(16),以及瓦片的形狀(4、4),我怎樣才能把這個一維數組重新變成瓦片,然后創建一個二維數組從那些瓷磚上看,哪一個看起來像從一開始的那個?

編輯:我出去了幾天,抱歉耽擱了! 問題是我有一個扁平的一維數組,因為我想將它重塑為一個形式的外部實用程序,我從原始數組中得到,所以類似於:

    arr (with a shape (8, 12, 1))
        |
        |  tile the array (using Iosif 
        |  Doundoulakis's method)
        V 
    tiled_arr = arr.reshape(2, 3, 4, 4, 1)
        |
        | flatten the tiled array
        V 
    tiled_arr.flatten('C')
        |
        | pass to the external utility
        V 
    it returns the same flat array, for now, but it wouldn't in the nearest future, so reformatting tiled_array is not an option
        |
        | pass it to a reshaping function in question
        V 
    It should reshape the flat array back into (8, 12, 1), which is the shape of the original array arr

我昨天想出了這個代碼:

def reshape(flat_array, original_array):

    a = np.array([np.split(flat_array, 16)]).reshape(original_array.shape[1] // 4, 4, original_array.shape[0] // 4, 4, original_array.shape[2])

    b = a.reshape(2, 3, 4, 4)
    return b.swapaxes(1, 2).reshape(original_array.shape)

...而且它有效,我得到了我想要的結果。 但在我看來,它至少可以優化一點。

我認為這實際上就像另一個swapaxesreshape一樣簡單。 首先,您需要再次調用swapaxes(1, 2)以撤消上一次調用。 然后只需重塑回a的形狀。

>>> tiles
array([[[[[ 0],
          [ 0],
          [ 1],
          [ 3]],

         [[ 0],
          [ 0],
          [ 4],
          [ 0]],
          ...
          ]]])

>>> tiles.swapaxes(1, 2).reshape(a.shape)
array([[ 0,  0,  1,  3,  4,  5, 12,  0,  0,  0,  0,  0],
       [ 0,  0,  4,  0, 13,  0,  0,  2,  0,  0,  0,  0],
       [ 1,  2,  3,  4,  5,  6,  7,  8,  0,  0,  0,  0],
       [ 5,  4,  9,  0,  3,  0,  7,  2,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  1,  0,  5,  7,  5,  0,  1,  0],
       [ 0,  0,  0,  0,  0,  5, 12,  3,  0,  4, 12,  3],
       [ 0,  0,  0,  0,  5, 14,  0,  9, 10,  2,  0, 15]])

如果您沒有a.shape ,您可能可以使用(S[0]*S[2], S[1]*S[3])之類的東西來計算它,其中Stiles.shape

tiles.swapaxes(1, 2).reshape(x.shape[0] * x.shape[2], x.shape[1] * x.shape[3])

我不明白你到底想要什么,但我猜你正在尋找類似我之前的答案的東西(對於你的例子,它得到shape = (6, 4 ,4) ):

a.reshape(a.shape[0] // 4, 4, -1, 4).swapaxes(1, 2).reshape(a.size // (4 * 4), 4, 4)

您需要將返回數組重新整形為a.size // (4 * 4), 4, 4) (如果您確定可以被 4 或 16 整除的形狀……),因此平鋪函數必須更改為:

def tiling(arr):
    b = arr.reshape(arr.shape[0] // 4, 4, arr.shape[1] // 4, 4, 1)
    return b.swapaxes(1, 2).reshape(arr.size // (4 * 4), 4, 4)

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

Iosif Doundoulakis 方法的好處之一是平鋪數組和原始數組共享內存。

original_array = np.array([
    [0, 0, 1, 3, 4, 5, 12, 0, 0, 0, 0, 0],
    [0, 0, 4, 0, 13, 0, 0, 2, 0, 0, 0, 0],
    [1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0],
    [5, 4, 9, 0, 3, 0, 7, 2, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 5, 7, 5, 0, 1, 0],
    [0, 0, 0, 0, 0, 5, 12, 3, 0, 4, 12, 3],
    [0, 0, 0, 0, 5, 14, 0, 9, 10, 2, 0, 15],
])

tile_rows, tile_cols = tile_shape = (2, 4)

grid_rows, grid_cols = grid_shape = (original_array.shape[0] // tile_shape[0],
                                     original_array.shape[1] // tile_shape[1])

tiled_array = original_array \
    .reshape((grid_rows, tile_rows, grid_cols, tile_cols, 1)) \
    .swapaxes(1, 2)

print(np.shares_memory(tiled_array, original_array))  # True

tiled_arrayoriginal_array的視圖; tiled_array的任何就地修改也適用於original_array

tiled_array[0, 0] = 99
print(original_array)

印刷

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

正如其他人指出的那樣,可以通過將軸交換回來並重新整形來反轉轉換,

recovered_original_array = tiled_array \
    .swapaxes(1, 2) \
    .reshape((grid_rows * tile_rows, grid_cols * tile_cols))

print(np.all(recovered_original_array == original_array))  # True

這三個數組都共享內存。

print(np.shares_memory(recovered_original_array, original_array)) # True

但是,當您使用flatten方法展平數組時,這個有用的屬性會被破壞,因為flatten總是返回副本而不是視圖,

flat_array = tiled_array.flatten()
print(np.shares_memory(flat_array, original_array))  # False

使用-1作為參數調用的reshape方法,如果可能,將返回一個扁平視圖,否則將返回一個副本。 在這種情況下,它返回一個副本。

flat_array = tiled_array.reshape(-1)
print(np.shares_memory(flat_array, original_array))  # False

無論哪種方式,您都可以輕松地從flat_array恢復tiled_array

recovered_tiled_array = flat_array.reshape((grid_rows, grid_cols, tile_rows, tile_cols, 1))
print(np.shares_memory(recovered_tiled_array, tiled_array))  # False
print(np.all(recovered_tiled_array == tiled_array))  # True

據我所知,沒有辦法按照您需要的順序制作原始陣列的平面陣列視圖。 但是,您可以制作平鋪陣列的平面視圖,然后進行處理。 為此,請復制tiled_array

tiled_array = original_array \
    .reshape((grid_rows, tile_rows, grid_cols, tile_cols, 1)) \
    .swapaxes(1, 2).copy()

print(np.shares_memory(tiled_array, original_array))  # False

允許相同的平面視圖

flat_array = tiled_array.reshape(-1)

print(np.shares_memory(flat_array, tiled_array))  # True

flat_array[:] = function_on_flat_array(flat_array)  # changes apply automatically to flat_array

暫無
暫無

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

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