poeticcapybara
poeticcapybara

Reputation: 575

How to convert a 3d numpy array to 2d

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 hstacking (and/or vstacking) them or adding an extra dimension and reshaping?

Upvotes: 34

Views: 40444

Answers (3)

Soudipta Dutta
Soudipta Dutta

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

cottontail
cottontail

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)

result1


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.

result2

reshaped_arr = arr.reshape(2,2,2,2).transpose(1,2,0,3).reshape(4,-1)

Upvotes: 0

unutbu
unutbu

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

Related Questions