5

I have a matrix:

A = [ [1,2],
      [3,4],
      [5,6] ]

and a vector of values:

V = [4,6,2]

I would like to reorder A by 2nd column, using values from V. The result should be:

A = [ [3,4],
      [5,6], 
      [1,2] ] # 2nd columns' values have the same order as V

How to do it?

2 Answers 2

7

First, we need to find the indicies of the values in the second column of A that we'd need to match the order of V. In this case, that's [1,2,0]. Once we have those, we can just use numpy's "fancy" indexing to do the rest.

So, you might do something like this:

import numpy as np
A = np.arange(6).reshape((3,2)) + 1
V = [4,6,2]
column = A[:,1].tolist()
order = [column.index(item) for item in V]
print A[order,:]

If you want to avoid python lists entirely, then you can do something like what's shown below. It's hackish, and there may be a better way, though...

We can abuse numpy.unique to do this... What I'm doing here is depending on a particular implementation detail (unique seems to start at the end of the array) which could change at any time... That's what makes it an ugly hack.

import numpy as np
A = np.arange(6).reshape((3,2)) + 1
V = np.array([4,6,2])
vals, order = np.unique(np.hstack((A[:,1],V)), return_inverse=True)
order = order[-V.size:]
print A[order,:]
Sign up to request clarification or add additional context in comments.

1 Comment

Well, there is, but it seems that you don't want A sorted by V... (If you did, you'd just need to use np.argsort and then use indexing, or another similar method.) You want A in the same order as V. Then again, there probably is a simpler way than what I'm describing...
6

@JoeKington's numpy solution is very clever, but it relies on A[:,1] being in sorted order. Here is a fix for the general case:

import numpy as np

np.random.seed(1)
N=5
A = np.arange(2*N).reshape((-1,2))+100
np.random.shuffle(A)
print(A)

If A looks like this:

[[104 105]
 [102 103]
 [108 109]
 [100 101]
 [106 107]]

and V

V = A[:,1].copy()
np.random.shuffle(V)
print(V)

looks like this:

[105 109 107 101 103]

then we use Joe's solution:

vals, order = np.unique(np.hstack((A[:,1],V)), return_inverse=True)

but save both the order of A[:,1] and V:

a_order = order[:V.size]
v_order = order[-V.size:]

and sort A (by forming A[np.argsort(a_order)]) before reordering with v_order:

print A[np.argsort(a_order)][v_order]

[[104 105]
 [108 109]
 [106 107]
 [100 101]
 [102 103]]

(A[np.argsort(a_order)] is A sorted according to its second column.)


Note that np.unique always returns the array in sorted order. The documentation guarantees with return_inverse=True that the returned indices are the indices of the unique array that reconstructs the original array. That is, if you call np.unique like this:

uniq_arr, indices = np.unique(arr, return_inverse=True)

you are guaranteed that

unique_arr[indices] = arr

Because you can rely on this relationship, Joe's method does not depend on a mere implementation detail -- unique will always behave this way. (Famous last words -- considering what happened to the order of output arguments returned by np.unique1d ... but never mind that :))

1 Comment

Quite nice, and good points in all cases! I wasn't thinking it through enough.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.