Numpy: argsort gives wrong results

Created on 8 Mar 2017  ·  4Comments  ·  Source: numpy/numpy

The argsort function seems to be broken. Looking at the code provided, the argsort for rows [0, 1] is correct but it's messed up for rows [2, 3].
I tested this on different NumPy installations and versions 1.11.0 and 1.12.0

import numpy as np

vec = np.array([
    [-1.4, -1.2,  1.3],
    [-3.6,  3.9, -3.7],
    [-2.3,  1.5, -2. ],
    [-2.6,  2.4, -1.6]
    ])

In [1]: np.argsort(-vec, axis=1)
Out[1]: 
array([[2, 1, 0],
       [1, 0, 2],
       [1, 2, 0],
       [1, 2, 0]])
53 - Invalid

Most helpful comment

This is the second google result for "np argsort wrong".

The explanation on the docs page is unclear (to me). I will add my own explanation here in the hopes that it helps someone:

x = numpy.array([1.48,1.31,0.0,0.8])
print x.argsort()

>[2 3 1 0]

Some people might expect this to instead give [3, 2, 0, 1], i.e., the 0th element in the unsorted array should be the 3rd element in the sorted array.

What it actually does is provide indices such that x[np.argsort(x)] will give you a sorted list, i.e., [0.0, 0.8, 1.31, 1.48]. Put another way, [2 3 1 0] tells you that the 0th element of the sorted array is the 2nd element of the unsorted array.

If you really want to get [3, 2, 0, 1] as an output, you can instead do

np.argsort(np.argsort(x))
>[3 2 0 1]

Alternatively, if you're just really off-base like I was and only want, say, the indices of the 3 largest elements in x:

np.argsort(x)[:-4:-1]
>[0, 1, 3]

All 4 comments

Can't see anything wrong with the result, print out vec[np.arange(4)[:, np.newaxis], np.argsort(-vec, axis=1)] and see that it looks good.

This is the second google result for "np argsort wrong".

The explanation on the docs page is unclear (to me). I will add my own explanation here in the hopes that it helps someone:

x = numpy.array([1.48,1.31,0.0,0.8])
print x.argsort()

>[2 3 1 0]

Some people might expect this to instead give [3, 2, 0, 1], i.e., the 0th element in the unsorted array should be the 3rd element in the sorted array.

What it actually does is provide indices such that x[np.argsort(x)] will give you a sorted list, i.e., [0.0, 0.8, 1.31, 1.48]. Put another way, [2 3 1 0] tells you that the 0th element of the sorted array is the 2nd element of the unsorted array.

If you really want to get [3, 2, 0, 1] as an output, you can instead do

np.argsort(np.argsort(x))
>[3 2 0 1]

Alternatively, if you're just really off-base like I was and only want, say, the indices of the 3 largest elements in x:

np.argsort(x)[:-4:-1]
>[0, 1, 3]

If you really want to get [3, 2, 0, 1] as an output, you can instead do

Doing this will be faster:

a = np.empty(len(x), np.intp)
a[np.argsort(x)] = np.arange(len(x))

9880 suggests adding this to numpy as np.invert_permutation(np.argsort(x))

@rossbar, @bjnath: Perhaps worth extracting stuff from @ghost's comment above and putting it in the docs? I've added some more crosslinks to show more examples of confusion.

Was this page helpful?
0 / 5 - 0 ratings