[英]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)
...而且它有效,我得到了我想要的結果。 但在我看來,它至少可以優化一點。
我認為這實際上就像另一個swapaxes
和reshape
一樣簡單。 首先,您需要再次調用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])
之類的東西來計算它,其中S
是tiles.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_array
是original_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.