Rearrange columns of numpy 2D array
Asked Answered
A

4

83

Is there a way to change the order of the columns in a numpy 2D array to a new and arbitrary order? For example, I have an array

array([[10, 20, 30, 40, 50],
       [ 6,  7,  8,  9, 10]])

and I want to change it into, say

array([[10, 30, 50, 40, 20],
       [ 6,  8, 10,  9,  7]])

by applying the permutation

0 -> 0
1 -> 4
2 -> 1
3 -> 3
4 -> 2

on the columns. In the new matrix, I therefore want the first column of the original to stay in place, the second to move to the last column and so on.

Is there a numpy function to do it? I have a fairly large matrix and expect to get even larger ones, so I need a solution that does this quickly and in place if possible (permutation matrices are a no-go)

Thank you.

Abshier answered 28/11, 2013 at 11:39 Comment(0)
Z
103

This is possible in O(n) time and O(n) space using fancy indexing:

>>> import numpy as np
>>> a = np.array([[10, 20, 30, 40, 50],
...               [ 6,  7,  8,  9, 10]])
>>> permutation = [0, 4, 1, 3, 2]
>>> idx = np.empty_like(permutation)
>>> idx[permutation] = np.arange(len(permutation))
>>> a[:, idx]  # return a rearranged copy
array([[10, 30, 50, 40, 20],
       [ 6,  8, 10,  9,  7]])
>>> a[:] = a[:, idx]  # in-place modification of a

Note that a[:, idx] is returning a copy, not a view. An O(1)-space solution is not possible in the general case, due to how numpy arrays are strided in memory.

Zaneta answered 28/11, 2013 at 11:51 Comment(3)
Fancy indexing does not mutate the matrix in-place. The OP asked for in-place methods. Please take a look at this answer: #23820299Kvass
OP asked for "in place if possible". In this case, it is not possible (due to the way ndarray is strided in memory)Zaneta
Sure, so maybe point out that this doesn't mutate the matrix in-place, so that it is clear for people who get here from google?Kvass
S
29

The easiest way in my opinion is:

a = np.array([[10, 20, 30, 40, 50],
              [6,  7,  8,  9,  10]])
print(a[:, [0, 2, 4, 3, 1]])

the result is:

[[10 30 50 40 20]
 [6  8  10 9  7 ]]
Southwester answered 17/11, 2020 at 0:38 Comment(2)
Just like how MATLAB does it. This may not be as efficient as the fancy indexing version, but it is much less complex and easier to read. Great choice when you don't want to explain the fancy indexing time save in your comments to colleagues.Sommer
Can you modify the rows, using the method like this?Brendin
S
8

I have a matrix based solution for this, by post-multiplying a permutation matrix to the original one. This changes the position of the elements in original matrix

import numpy as np

a = np.array([[10, 20, 30, 40, 50],
       [ 6,  7,  8,  9, 10]])

# Create the permutation matrix by placing 1 at each row with the column to replace with
your_permutation = [0,4,1,3,2]

perm_mat = np.zeros((len(your_permutation), len(your_permutation)))

for idx, i in enumerate(your_permutation):
    perm_mat[idx, i] = 1

print np.dot(a, perm_mat)
Sigfried answered 10/9, 2018 at 23:34 Comment(2)
Hello and welcome to SO. This answer appears to do the trick, but would you mind editing and explaining what your code is doing? I understand it, but someone else may not and without the proper explanation we are teaching what to do and not how to do something.Wolfgram
In one line, this is np.dot(a, np.eye(a.shape[1], dtype=a.dtype)[your_permutation]). It's OK for small arrays, but will perform very slowly with big data. Note: O.P. mentioned in the question "permutation matrices are a no-go" but it's probably still worth having the matrix solution here for benefit of other users that find this in the search, and don't need performance. +1Zaneta
S
0

If you're looking for any random permuation, you can do it in one line if you transpose columns into rows, permute the rows, then transpose back:

a = np.random.permutation(a.T).T
Smiga answered 22/8, 2020 at 22:55 Comment(3)
this line doesn't gives the appropriate resultHapp
Oh, perhaps I've misunderstood the question. I assumed that the permutation was supposed to be randomly generated, but now I see that's not the case. This line is indeed highly unlikely to produce the specific permutation given in the question. I'm editing to clarify that.Smiga
@FrankSeidl I just read your commend and laughed so hard I had to upvote. "Highly unlikely" indeed. roflmao.Lowis

© 2022 - 2024 — McMap. All rights reserved.