Reputation: 575
I have a 3d matrix like this
np.arange(16).reshape((4,2,2))
array([[[ 0, 1],
[ 2, 3]],
[[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11]],
[[12, 13],
[14, 15]]])
and would like to stack them in grid format, ending up with
array([[ 0, 1, 4, 5],
[ 2, 3, 6, 7],
[ 8, 9, 12, 13],
[10, 11, 14, 15]])
Is there a way of doing without explicitly hstack
ing (and/or vstack
ing) them or adding an extra dimension and reshaping?
Upvotes: 34
Views: 40444
Reputation: 2122
Use Einsum :
import numpy as np
# Original 3D array
a = np.arange(16).reshape((4, 2, 2))
print(a)
'''
[[[ 0 1]
[ 2 3]]
[[ 4 5]
[ 6 7]]
[[ 8 9]
[10 11]]
[[12 13]
[14 15]]]
'''
using_einsum = np.einsum('abcd -> acbd',a.reshape(2,2,2,2)).reshape(4,4)
print(using_einsum)
'''
[[ 0 1 4 5]
[ 2 3 6 7]
[ 8 9 12 13]
[10 11 14 15]]
'''
Method 2(Using Transpose) :
import numpy as np
# Original 3D array
a = np.arange(16).reshape((4, 2, 2))
res = a.reshape(2,2,2,2).transpose(0,2,1,3).reshape(4,4)
print(res)
'''
[[ 0 1 4 5]
[ 2 3 6 7]
[ 8 9 12 13]
[10 11 14 15]]
'''
Method 3(Using swapaxes) :
import numpy as np
# Original 3D array
a = np.arange(16).reshape((4, 2, 2))
res = a.reshape(2, 2, 2, 2).swapaxes(1, 2).reshape(4, 4)
print(res)
'''
[[ 0 1 4 5]
[ 2 3 6 7]
[ 8 9 12 13]
[10 11 14 15]]
'''
Method :
import numpy as np
from skimage.util import view_as_blocks
# Define the input array
arr = np.arange(16).reshape((4, 2, 2))
print(arr)
'''
[[[ 0 1]
[ 2 3]]
[[ 4 5]
[ 6 7]]
[[ 8 9]
[10 11]]
[[12 13]
[14 15]]]
'''
print(arr.shape)#(4, 2, 2)
# Specify the block shape for the 3D array
block_shape = (2,1,2)
# Use view_as_blocks to split the array into blocks
blocks = view_as_blocks(arr, block_shape)
print(blocks)
'''
[[[[[[ 0 1]]
[[ 4 5]]]]
[[[[ 2 3]]
[[ 6 7]]]]]
[[[[[ 8 9]]
[[12 13]]]]
[[[[10 11]]
[[14 15]]]]]]
'''
# Reshape and rearrange the blocks into the desired 2D array
blocks_reshaped = blocks.reshape(2, 2, 2, 2)
'''
[[[[ 0 1]
[ 4 5]]
[[ 2 3]
[ 6 7]]]
[[[ 8 9]
[12 13]]
[[10 11]
[14 15]]]]
'''
res = blocks_reshaped.reshape(4,4)
'''
[[ 0 1 4 5]
[ 2 3 6 7]
[ 8 9 12 13]
[10 11 14 15]]
'''
Upvotes: 0
Reputation: 23021
The convert a 3d array to a 2d one, transpose()
is a very useful function. For example, to derive the expected result in the OP, after reshaping by adding an extra dimension, the second and third axes could be swapped using transpose()
.
arr = np.arange(16).reshape(4,2,2)
reshaped_arr = arr.reshape(2,2,2,2).transpose(0,2,1,3).reshape(4,-1)
On the surface, it does the same job as swapaxes()
but since transpose()
allows any permutation of axes, it's more flexible. For example, to make the following transformation, two axes must be swapped, so swapaxes()
will have to called twice but it can be handled with a single transpose()
call.
reshaped_arr = arr.reshape(2,2,2,2).transpose(1,2,0,3).reshape(4,-1)
Upvotes: 0
Reputation: 879103
In [27]: x = np.arange(16).reshape((4,2,2))
In [28]: x.reshape(2,2,2,2).swapaxes(1,2).reshape(4,-1)
Out[28]:
array([[ 0, 1, 4, 5],
[ 2, 3, 6, 7],
[ 8, 9, 12, 13],
[10, 11, 14, 15]])
I've posted more general functions for reshaping/unshaping arrays into blocks, here.
Upvotes: 44