undo or reverse argsort(), python undo or reverse argsort(), python numpy numpy

undo or reverse argsort(), python


There are probably better solutions to the problem you are actually trying to solve than this (performing an argsort usually precludes the need to actually sort), but here you go:

>>> import numpy as np>>> a = np.random.randint(0,10,10)>>> aa = np.argsort(a)>>> aaa = np.argsort(aa)>>> a # originalarray([6, 4, 4, 6, 2, 5, 4, 0, 7, 4])>>> a[aa] # sortedarray([0, 2, 4, 4, 4, 4, 5, 6, 6, 7])>>> a[aa][aaa] # undonearray([6, 4, 4, 6, 2, 5, 4, 0, 7, 4])


For all those still looking for an answer:

In [135]: r = rand(10)In [136]: i = argsort(r)In [137]: r_sorted = r[i]In [138]: i_rev = zeros(10, dtype=int)In [139]: i_rev[i] = arange(10)In [140]: allclose(r, r_sorted[i_rev])Out[140]: True


I'm not sure how best to do it in numpy, but, in pure Python, the reasoning would be:

aargsort is holding a permutation of range(len(a)) telling you where the items of aSort came from -- much like, in pure Python:

>>> x = list('ciaobelu')>>> r = range(len(x))>>> r.sort(key=x.__getitem__)>>> r[2, 4, 0, 5, 1, 6, 3, 7]>>> 

i.e., the first argument of sorted(x) will be x[2], the second one x[4], and so forth.

So given the sorted version, you can reconstruct the original by "putting items back where they came from":

>>> s = sorted(x)>>> s['a', 'b', 'c', 'e', 'i', 'l', 'o', 'u']>>> original = [None] * len(s)>>> for i, c in zip(r, s): original[i] = c... >>> original['c', 'i', 'a', 'o', 'b', 'e', 'l', 'u']>>> 

Of course there are going to be tighter and faster ways to express this in numpy (which unfortunately I don't know inside-out as much as I know Python itself;-), but I hope this helps by showing the underlying logic of the "putting things back in place" operation you need to perform.