Babak
Babak

Reputation: 487

Reshaping/Combining several sub-matrices to one matrix in multi-dimensional space

I have a 5D binary array 'a' of size (2, 2, 4, 2, 2). The structure looks like this, for example:

a[0,0]:
[[[ 0.  1.]
  [ 0.  0.]]

 [[ 0.  0.]
  [ 0.  1.]]

 [[ 0.  0.]
  [ 0.  1.]]

 [[ 0.  0.]
  [ 1.  0.]]]

What I want to do is to make a (2,2,4,4) matrix that combines the 2x2 matrices in the last two axis, but in a squared structure.

The result should look like this:

result[0,0]:
[[0. 1. 0. 0.]
 [0. 0. 0. 1.]
 [0. 0. 0. 0.]
 [0. 1. 1. 0.]]

I hope this is clear enough. If I put the brackets of original matrices in results, it looks like this:

result[0,0]:
[[[0. 1. [0. 0.]
 [0. 0.] 0. 1.]]
 [[0. 0. [0. 0.]
 [0. 1.] 1. 0.]]]

Upvotes: 3

Views: 633

Answers (2)

hpaulj
hpaulj

Reputation: 231425

First, it is better to index your array like a[0,0] or a[0,0,...] or a[0,0,:,:].

Does a.reshape(2,2, 4,4) do what you want? That retains all values, but reshapes the inner most (2,2) arrays into (4,) arrays.

Looking more closely it looks like you want to reorder values in the inner arrays. That is not entirely obvious from your description. I had to carefully match up values between the displays. In particular it's only 2 of the subarrays that are unabiguous:

[[ 0.  0.]
  [ 0.  1.]]

 [[ 0.  0.]
  [ 1.  0.]]]

[0. 0. 0. 0.]
 [0. 1. 1. 0.]]

What we will need to do is transpose the last 2 axes before reshaping.

This might do the trick:

a.transpose(0,1,2,4,3).reshape(2,2,4,4)

It works with np.ones((2,2,4,2,2)), but I haven't tested it with numbers that duplicate your question - because you did not give a test case that can be cut-n-pasted.


oops - looks like Divakar got it right. We need to break up the 4 dimension into 2,2, and perform the transpose across dimensions.

In [290]: a=np.array([[[0,1],[0,0]],[[0,0],[0,1]],[[0,0],[0,1]],[[0,0],[1,0]]])
In [291]: a
Out[291]: 
array([[[0, 1],
        [0, 0]],

       [[0, 0],
        [0, 1]],

       [[0, 0],
        [0, 1]],

       [[0, 0],
        [1, 0]]])
In [292]: a.reshape(2,2,2,2).transpose(0,2,1,3).reshape(4,4)
Out[292]: 
array([[0, 1, 0, 0],
       [0, 0, 0, 1],
       [0, 0, 0, 0],
       [0, 1, 1, 0]])

Here's a clearer example:

In [303]: a=np.arange((4*2*2)).reshape(4,2,2)
In [304]: a.reshape(2,2,2,2).transpose(0,2,1,3).reshape(4,4)
Out[304]: 
array([[ 0,  1,  4,  5],
       [ 2,  3,  6,  7],
       [ 8,  9, 12, 13],
       [10, 11, 14, 15]])

It would be even better if each of the dimensions was different, so there'd even less ambiguity as to which ones are being combined.

In [308]: a=np.arange((6*5*7)).reshape(6,5,7)
In [309]: a.reshape(2,3,5,7).transpose(0,2,1,3).reshape(10,21)

Upvotes: 2

Divakar
Divakar

Reputation: 221604

It seems you are breaking the third axis from (4) into (2,2) and bringing in the first half of the split axes to the second last axes position. So, there are two ways to achieve such an output using np.reshape and np.transpose, like so -

out = a.reshape(2,2,2,2,2,2).transpose(0,1,3,4,2,5).reshape(2,2,4,4)

out = a.reshape(2,2,2,-1,2).transpose(0,1,3,2,4).reshape(2,2,4,4)

Sample run -

In [69]: a[0][0]
Out[69]: 
array([[[49, 91],
        [10, 32]],

       [[71, 27],
        [50, 64]],

       [[ 9, 41],
        [73, 52]],

       [[54, 85],
        [53, 36]]])

In [70]: out1 = a.reshape(2,2,2,2,2,2).transpose(0,1,3,4,2,5).reshape(2,2,4,4)

In [71]: out2 = a.reshape(2,2,2,-1,2).transpose(0,1,3,2,4).reshape(2,2,4,4)

In [72]: out1[0][0]
Out[72]: 
array([[49, 91,  9, 41],
       [10, 32, 73, 52],
       [71, 27, 54, 85],
       [50, 64, 53, 36]])

In [73]: out2[0][0]
Out[73]: 
array([[49, 91,  9, 41],
       [10, 32, 73, 52],
       [71, 27, 54, 85],
       [50, 64, 53, 36]])

Upvotes: 3

Related Questions