The numpy.argsort() function is a powerful tool in NumPy for finding the indices that would sort an array. By default, it returns indices for an ascending sort. However, a common requirement is to get the indices that would sort an array in descending order, for example, to find the indices of the largest N elements or to process data from largest to smallest.
This guide will comprehensively demonstrate several effective methods to achieve a descending order argsort in NumPy. We'll cover techniques such as negating the array before sorting, using slice reversal [::-1], leveraging numpy.flip(), and multiplying the array by -1, explaining the logic behind each approach.
Understanding numpy.argsort() (Ascending Order by Default)
numpy.argsort(a, axis=-1, kind=None, order=None) returns an array of indices of the same shape as a that would sort a along the specified axis. By default, the sort is ascending.
import numpy as np
original_array = np.array([10, 50, 5, 80, 25])
print(f"Original array: {original_array}")
ascending_indices = np.argsort(original_array)
print(f"Indices for ascending sort: {ascending_indices}")
print(f"Array sorted ascending: {original_array[ascending_indices]}")Output:
Original array: [10 50 5 80 25]
Indices for ascending sort: [2 0 4 1 3]
Array sorted ascending: [5 10 25 50 80]Our goal is to get indices like [3, 1, 4, 0, 2] which would sort original_array in descending order.
Method 1: Negating the Array Before argsort() (Recommended for Numeric Arrays)
For numeric arrays, the simplest and often most intuitive way to get descending argsort indices is to sort the negation of the array in ascending order. When you negate an array, the smallest elements become the largest (in terms of their new negative value being most negative) and vice versa.
import numpy as np
original_array = np.array([10, 50, 5, 80, 25])
negated_array = -original_array
print(f"Negated array: {negated_array}")
descending_indices_negation = np.argsort(negated_array)
print(f"Indices for descending sort (by negating): {descending_indices_negation}")
print(f"Array sorted descending: {original_array[descending_indices_negation]}")Output:
Negated array: [-10 -50 -5 -80 -25]
Indices for descending sort (by negating): [3 1 4 0 2]
Array sorted descending: [80 50 25 10 5]Method 2: Reversing Ascending argsort() Indices with Slice [::-1]
This method first gets the indices for an ascending sort and then reverses that array of indices using slice notation [::-1].
import numpy as np
original_array = np.array([10, 50, 5, 80, 25])
ascending_indices = np.argsort(original_array)
descending_indices_slice = ascending_indices[::-1]
print(f"Indices for descending sort (using slice [::-1]): {descending_indices_slice}")
print(f"Array sorted descending: {original_array[descending_indices_slice]}")Output:
Indices for descending sort (using slice [::-1]): [3 1 4 0 2]
Array sorted descending: [80 50 25 10 5]Method 3: Reversing Ascending argsort() Indices with numpy.flip()
Similar to slice reversal, numpy.flip(arr, axis=None) reverses the order of elements in an array along the given axis (or all axes if axis=None). For a 1D array of indices, it effectively reverses it.
import numpy as np
original_array = np.array([10, 50, 5, 80, 25])
ascending_indices = np.argsort(original_array)
descending_indices_flip = np.flip(ascending_indices)
print(f"Indices for descending sort (using np.flip()): {descending_indices_flip}")
print(f"Array sorted descending: {original_array[descending_indices_flip]}")Output:
Indices for descending sort (using np.flip()): [3 1 4 0 2]
Array sorted descending: [80 50 25 10 5]Method 4: Multiplying the Array by -1 Before argsort() (Similar to Negation)
Multiplying a numeric array by -1 has the same effect as negating it with the unary minus operator (-array). This method also relies on inverting the order by changing the signs of the numbers.
import numpy as np
original_array = np.array([10, 50, 5, 80, 25])
multiplied_array = original_array * -1
print(f"Array multiplied by -1: {multiplied_array}")
descending_indices_multiply = np.argsort(multiplied_array)
print(f"Indices for descending sort (by multiplying by -1): {descending_indices_multiply}")
print(f"Array sorted descending: {original_array[descending_indices_multiply]}")Output:
Array multiplied by -1: [-10 -50 -5 -80 -25]
Indices for descending sort (by multiplying by -1): [3 1 4 0 2]
Array sorted descending: [80 50 25 10 5]Selecting Indices of the Top N Largest Elements
Once you have the indices for a descending sort, you can easily get the indices of the top N largest elements by slicing the resulting index array.
import numpy as np
original_array = np.array([10, 50, 5, 80, 25, 90, 15]) # Added more elements
descending_indices = (-original_array).argsort()
N = 3 # We want indices of the top 3 largest elements
indices_of_top_N = descending_indices[:N]
print(f"Original array: {original_array}")
print(f"All indices for descending sort: {descending_indices}")
print(f"Indices of the top {N} largest elements: {indices_of_top_N}")
print(f"The top {N} largest elements themselves: {original_array[indices_of_top_N]}")Output:
Original array: [10 50 5 80 25 90 15]
All indices for descending sort: [5 3 1 4 6 0 2]
Indices of the top 3 largest elements: [5 3 1]
The top 3 largest elements themselves: [90 80 50]Choosing the Best Method
- Negating the array (
(-arr).argsort()): This is very common, clear, and efficient for numeric arrays. It directly reflects the idea of sorting by "largest first" by making largest positive numbers the "smallest" negative numbers. - Slicing
[::-1]ornp.flip(): These are generally applicable to any array of indices returned byargsort()regardless of the original array's dtype (as long asargsortitself is meaningful for that dtype). They are good general-purpose ways to reverse an ordered set of indices. Performance differences between[::-1]andnp.flip()on 1D arrays are usually negligible. - Multiplying by -1: Functionally the same as negating for numeric arrays, but slightly more verbose.
For numeric data, negating is often the most direct. For a general way to reverse any argsort result, [::-1] is very Pythonic.
Conclusion
While numpy.argsort() defaults to providing indices for an ascending sort, you can easily obtain indices for a descending sort using several techniques:
- Negate the numeric array before calling
argsort():(-my_array).argsort(). - Perform an ascending
argsort()and then reverse the resulting index array using slice notation[::-1]:my_array.argsort()[::-1]. - Perform an ascending
argsort()and then reverse the index array usingnp.flip():np.flip(my_array.argsort()).
These methods allow you to effectively find the order of elements from largest to smallest, which is crucial for tasks like identifying top N values, ranking, or custom sorting procedures in NumPy.