[SciPy-User] reversing or avoiding the need to reverse argsort()

Anne Archibald peridot.faceted at gmail.com
Sat Mar 20 12:09:53 EDT 2010


On 20 March 2010 11:37, Vincent Davis <vincent at vincentdavis.net> wrote:

> What I want to do is simple but not sure the best way to go about it.
>
> I have an array a, shape(a) = rXc I need to sort each column
> aargsort = a.argsort(axis=0)  # May use this later
> aSort = a.sort(axis=0)
>
> now average each row
> aSortRM = asort.mean(axis=1)
>
> now replace each col in a row with the row mean.
> is there a better way than this
>
> aWithMeans = ones_like(a)
> for ind in range(r)  # r = number of rows
>     aWithMeans[ind]* aSortRM[ind]
>
> Now I need to undo the sort I did in the first step.
> I think this is where I need the aargsort (argsort of a before any
> modification) I am kinda stumped on this step. Everything I think of is
> rather convoluted.
> Is it possible to do this whole process without actually rearranging the
> original array and just using the index info from the argsort() and would I
> want to do this?
>

First of all, there's no need to use both argsort and sort:

In [2]: A = np.random.randn(1000)

In [3]: I = A.argsort()

In [4]: B = A[I]

In [5]: np.all(np.diff(B)>=0)
Out[5]: True

Now, to invert the permutation I, the easiest way is just to argsort() it;
but this is N log N instead of order N, so there's another, slightly more
cumbersome, way to do it:

In [12]: Ij = np.zeros_like(I)

In [13]: Ij[I] = np.arange(len(I))

In [23]: AA = B[Ij]

In [24]: np.all(AA==A)
Out[24]: True

Alternatively, you can avoid ever creating the inverse permutation:

In [25]: AA[I] = B

In [26]: np.all(AA==A)
Out[26]: True

All of this is somewhat more painful with two-dimensional arrays, since
fancy and normal indexing do not mix well, and argsort returns something
peuliar, but it can be made to work:

In [51]: A = np.random.randn(100,100)

In [52]: I = np.argsort(A, axis=0)

In [54]: B=A[I,np.arange(A.shape[1])]

In [55]: AA = np.zeros_like(A)

In [56]: AA[I,np.arange(A.shape[1])] = B

In [57]: np.all(AA==A)
Out[57]: True

Now for processing B in place, that's a simpler problem:

In [58]: BB = np.zeros_like(B)

In [59]: BB[...] = np.mean(B,axis=1)

Here numpy's broadcasting rules take care of duplicating the entries of B as
needed to fill out BB. In fact we can dispense with BB entirely:

In [60]: AA[I,np.arange(A.shape[1])] = np.mean(B,axis=1)

So your code can be rewritten as the impenetrable three lines:

In [61]: AA = np.zeros_like(A)

In [62]: I = np.argsort(A,axis=0)

In [63]: AA[I,np.arange(A.shape[1])] =
np.mean(A[I,np.arange(A.shape[1])],axis=1)

Or, even less clearly, making I into what I think argsort should probably
return:

In [64]: I = np.argsort(A,axis=0), np.arange(A.shape[1])

In [65]: AA[I] = np.mean(A[I],axis=1)


Anne
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.scipy.org/pipermail/scipy-user/attachments/20100320/8c06cf70/attachment.html>


More information about the SciPy-User mailing list