4

Given the following input numpy array of shape(n**2 * m, m), with n=2 and m=5 :

A = np.array([[  71.87,   47.8 ,   24.84,   25.31,   15.43],
              [ 174.8 ,  131.84,   57.57,   76.53,   48.5 ],
              [   4.4 ,    2.  ,    1.6 ,    1.  ,    0.  ],
              [  28.71,   15.  ,   10.5 ,    4.17,    2.52],
              [ 222.8 ,  123.59,    7.72,  -39.33,    4.65],
              [ 156.84,  138.17,   21.75,   80.86,   44.55],
              [  89.5 ,  133.01, -114.69,    1.  , -167.7 ],
              [  21.25,   19.57, -177.65,   57.38, -119.75],
              [ 162.33,    7.72,  -51.72,  117.31,  -87.87],
              [  77.57,   26.75,   36.64,    6.99,   25.97],
              [ 276.6 ,  275.31, -128.61,  105.7 ,  -86.5 ],
              [ 135.5 ,  232.67,    9.15,   -5.25,  -48.62],
              [ 325.31,  238.17,  -32.69,   41.55,    3.32],
              [ 126.53,  118.36,  -13.64,  104.64,    7.66],
              [ 522.25,  176.  , -338.05,  265.95, -411.87],
              [  16.67,  116.75, -255.25,  109.61, -397.18],
              [  15.43,  267.15,  159.63,    3.32,   30.31],
              [  48.5 ,   83.93,   63.47,   17.66,   70.16],
              [ 321.25,  213.55,    1.  ,  368.13, -261.55],
              [ 107.52,    5.25,  -89.25,  423.44,  -80.89]])

How one could reshape and permute axes of A in order to obtain the following output B of shape (n*m, n*m) ?

B = np.array([[  71.87,  174.8 ,  222.8 ,  156.84,  162.33,   77.57,  325.31,  126.53,   15.43,   48.5 ],
              [   4.4 ,   28.71,   89.5 ,   21.25,  276.6 ,  135.5 ,  522.25,   16.67,  321.25,  107.52],
              [  47.8 ,  131.84,  123.59,  138.17,    7.72,   26.75,  238.17,  118.36,  267.15,   83.93],
              [   2.  ,   15.  ,  133.01,   19.57,  275.31,  232.67,  176.  ,  116.75,  213.55,    5.25],
              [  24.84,   57.57,    7.72,   21.75,  -51.72,   36.64,  -32.69,  -13.64,  159.63,   63.47],
              [   1.6 ,   10.5 , -114.69, -177.65, -128.61,    9.15, -338.05, -255.25,    1.  ,  -89.25],
              [  25.31,   76.53,  -39.33,   80.86,  117.31,    6.99,   41.55,  104.64,    3.32,   17.66],
              [   1.  ,    4.17,    1.  ,   57.38,  105.7 ,   -5.25,  265.95,  109.61,  368.13,  423.44],
              [  15.43,   48.5 ,    4.65,   44.55,  -87.87,   25.97,    3.32,    7.66,   30.31,   70.16],
              [   0.  ,    2.52, -167.7 , -119.75,  -86.5 ,  -48.62, -411.87, -397.18, -261.55,  -80.89]])

This transformation is easily done using for loops but as I need to be efficient here, I am looking for a proper reshape-based solution with a bit of clarification on the logic behind it.

Any help would be greatly appreciated.

Yacola
  • 2,873
  • 1
  • 10
  • 27
  • 1
    Your values change, for example `162.33` to `162.34` index `[0,4]` in your expected output. What is the logic behind this? – Michael Szczesny Dec 03 '20 at 22:39
  • could you please provide us with for loop answer. It is not obvious how you reshaped the original one to last one – Ehsan Dec 03 '20 at 22:39
  • @MichaelSzczesny, sorry for that, the values came from different methods and may not be so close because of the specified precision in order to obtain small matrices for this question and np.set_printoptions kwargs. – Yacola Dec 03 '20 at 22:44

2 Answers2

2

It took a bit of squinting at your data to find out that, in the output, the columns of A have been chunked by blocks of n*n and tiled into nxn squares. So, for example, the B[:2, :2] has the values of A[:4, 0].

So, the key is to try to do put those blocks into contiguous dimensions, then use a transpose of the appropriate axes, before a final reshape.

Long story short:

B = np.reshape(np.reshape(A.T, (m, m, n, n)).transpose(0, 2, 1, 3), (n*m, n*m))
Pierre D
  • 24,012
  • 7
  • 60
  • 96
1

You can reshape blockwise with the usual reshape, swapaxes, reshape. @divakar posted a detailed explanation.

A.T.reshape(5,5,2,2).swapaxes(1,2).reshape(10,-1)

Out:

array([[  71.87,  174.8 ,  222.8 ,  156.84,  162.33,   77.57,  325.31, 126.53,    15.43,   48.5 ],
       [   4.4 ,   28.71,   89.5 ,   21.25,  276.6 ,  135.5 ,  522.25,  16.67,   321.25,  107.52],
       [  47.8 ,  131.84,  123.59,  138.17,    7.72,   26.75,  238.17, 118.36,   267.15,   83.93],
       [   2.  ,   15.  ,  133.01,   19.57,  275.31,  232.67,  176.  , 116.75,   213.55,    5.25],
       [  24.84,   57.57,    7.72,   21.75,  -51.72,   36.64,  -32.69, -13.64,   159.63,   63.47],
       [   1.6 ,   10.5 , -114.69, -177.65, -128.61,    9.15, -338.05, -255.25,    1.  ,  -89.25],
       [  25.31,   76.53,  -39.33,   80.86,  117.31,    6.99,   41.55,  104.64,    3.32,   17.66],
       [   1.  ,    4.17,    1.  ,   57.38,  105.7 ,   -5.25,  265.95,  109.61,  368.13,  423.44],
       [  15.43,   48.5 ,    4.65,   44.55,  -87.87,   25.97,    3.32,    7.66,   30.31,   70.16],
       [   0.  ,    2.52, -167.7 , -119.75,  -86.5 ,  -48.62, -411.87, -397.18, -261.55,  -80.89]])
Michael Szczesny
  • 4,911
  • 5
  • 15
  • 32