InvAdErZz
InvAdErZz

Reputation: 49

Re-order a numpy array python

I have a big two-dimensional array like this:

array([[ 1, 2, 3, 4, 5, 6, 7, 8],
       [ 9,10,11,12,13,14,15,16],
       [17,18,19,20,21,22,23,24],
       [25,26,27,28,29,30,31,32],
       [33,34,35,36,37,38,39,40],
       [41,42,43,44,45,46,47,48],
       ....])

and I need to convert it into:

array([ 1, 9,17, 2,10,18, 3,11,19, 4,12,20, 5,13,21, 6,14,22, 7,15,23, 8,16,24],
      [25,33,41,26,34,42,27,35,43,28,36,44,29,37,45,30,38,46,31,39,47,32,40,48],
      ...

Note that this should only be a demonstration what it should do.
The original array contains only boolean values and has the size of 512x8. In my example, I order only 3 rows with 8 elements into one row but what I really need are respectively 32 rows with 8 elements.

I am really sorry, but after 30 minutes of writing, this is the only description I got of my problem. I hope it is enough.

Upvotes: 1

Views: 87

Answers (2)

ali_m
ali_m

Reputation: 74172

I think you can achieve your desired result using two reshape operations and a transpose:

x = np.array([[ 1, 2, 3, 4, 5, 6, 7, 8],
              [ 9,10,11,12,13,14,15,16],
              [17,18,19,20,21,22,23,24],
              [25,26,27,28,29,30,31,32],
              [33,34,35,36,37,38,39,40],
              [41,42,43,44,45,46,47,48]])

y = x.reshape(2, 3, 8).transpose(0, 2, 1).reshape(2, -1)

print(repr(y))
# array([[ 1,  9, 17,  2, 10, 18,  3, 11, 19,  4, 12, 20,  5, 13, 21,  6, 14,
#         22,  7, 15, 23,  8, 16, 24],
#        [25, 33, 41, 26, 34, 42, 27, 35, 43, 28, 36, 44, 29, 37, 45, 30, 38,
#         46, 31, 39, 47, 32, 40, 48]])

To break that down a bit:

  1. @hpaulj's first reshape operation gives us this:

    x1 = x.reshape(2, 3, 8)
    print(repr(x1))
    # array([[[ 1,  2,  3,  4,  5,  6,  7,  8],
    #         [ 9, 10, 11, 12, 13, 14, 15, 16],
    #         [17, 18, 19, 20, 21, 22, 23, 24]],
    
    #        [[25, 26, 27, 28, 29, 30, 31, 32],
    #         [33, 34, 35, 36, 37, 38, 39, 40],
    #         [41, 42, 43, 44, 45, 46, 47, 48]]])
    print(x1.shape)
    # (2, 3, 8)
    
  2. In order to get the desired output we need to 'collapse' this array along the second dimension (with size 3), then along the third dimension (with size 8). The easiest way to achieve this sort of thing is to first transpose the array so that the dimensions you want to collapse along are ordered from first to last:

    x2 = x1.transpose(0, 2, 1)  # you could also use `x2 = np.rollaxis(x1, 1, 3)`
    print(repr(x2))
    # array([[[ 1,  9, 17],
    #     [ 2, 10, 18],
    #     [ 3, 11, 19],
    #     [ 4, 12, 20],
    #     [ 5, 13, 21],
    #     [ 6, 14, 22],
    #     [ 7, 15, 23],
    #     [ 8, 16, 24]],
    
    #    [[25, 33, 41],
    #     [26, 34, 42],
    #     [27, 35, 43],
    #     [28, 36, 44],
    #     [29, 37, 45],
    #     [30, 38, 46],
    #     [31, 39, 47],
    #     [32, 40, 48]]])
    print(x2.shape)
    # (2, 8, 3)
    
  3. Finally I can use reshape(2, -1) to collapse the array over the last two dimensions. The -1 causes numpy to infer the appropriate size in the last dimension based on the number of elements in x.

    y = x2.reshape(2, -2)
    

Upvotes: 5

hpaulj
hpaulj

Reputation: 231375

Looks like a starting point is to reshape it, for example

In [49]: x.reshape(2,3,8)
Out[49]: 
array([[[ 1,  2,  3,  4,  5,  6,  7,  8],
        [ 9, 10, 11, 12, 13, 14, 15, 16],
        [17, 18, 19, 20, 21, 22, 23, 24]],

       [[25, 26, 27, 28, 29, 30, 31, 32],
        [33, 34, 35, 36, 37, 38, 39, 40],
        [41, 42, 43, 44, 45, 46, 47, 48]]])

.ravel(order='F') doesn't get it right, so I think we need to swap some axes before flattening. It will need to be a copy.

Using @ali_m's transpose:

In [65]: x1=x.reshape(2,3,8)

In [66]: x1.transpose(0,2,1).flatten()
Out[66]: 
array([ 1,  9, 17,  2, 10, 18,  3, 11, 19,  4, 12, 20,  5, 13, 21,  6, 14,
       22,  7, 15, 23,  8, 16, 24, 25, 33, 41, 26, 34, 42, 27, 35, 43, 28,
       36, 44, 29, 37, 45, 30, 38, 46, 31, 39, 47, 32, 40, 48])

oops - there's an inner layer of nesting that's easy to miss

array([1,9,17,2,10,18,3,11,19,4,12,20,5,13,21,6,14,22,7,15,23,8,16,24],
      [25,33,41,26,34,42,27,35,43,28,36,44,29,37,45,30,38,46,31,39,47,32,40,4],

You are missing a [] set. So @ali_m got it right.

I'm tempted to delete this, but my trial and error might be instructive.

Upvotes: 1

Related Questions