¿Es posible usar argsort en orden descendente?

Considere el siguiente código:

avgDists = np.array([1, 8, 6, 9, 4]) ids = avgDists.argsort()[:n] 

Esto me da índices de los n elementos más pequeños. ¿Es posible usar este mismo argsort en orden descendente para obtener los índices de n elementos más altos?

Si niega una matriz, los elementos más bajos se convierten en los elementos más altos y viceversa. Por lo tanto, los índices de los n elementos más altos son:

 (-avgDists).argsort()[:n] 

Otra forma de razonar sobre esto, como se menciona en los comentarios , es observar que los grandes elementos vienen en último lugar en el argsort. Entonces, puedes leer desde la cola del argsort para encontrar los n elementos más altos:

 avgDists.argsort()[::-1][:n] 

Ambos métodos son O (n log n) en complejidad de tiempo, porque la llamada argsort es el término dominante aquí. Pero el segundo enfoque tiene una buena ventaja: reemplaza una negación O (n) de la matriz con un segmento O (1) . Si está trabajando con matrices pequeñas dentro de bucles, es posible que obtenga algunas mejoras de rendimiento al evitar esa negación, y si trabaja con matrices grandes, puede ahorrar en el uso de memoria porque la negación crea una copia de la matriz completa.

Tenga en cuenta que estos métodos no siempre dan resultados equivalentes: si se solicita una implementación de ordenamiento estable para argsort , por ejemplo, al pasar el argumento de palabra clave kind='mergesort' , entonces la primera estrategia conservará la estabilidad de clasificación, pero la segunda estrategia romperá la estabilidad (Es decir, las posiciones de elementos iguales se invertirán).

Al igual que Python, en que [::-1] invierte la matriz devuelta por argsort() y [:n] da los últimos n elementos:

 >>> avgDists=np.array([1, 8, 6, 9, 4]) >>> n=3 >>> ids = avgDists.argsort()[::-1][:n] >>> ids array([3, 1, 2]) 

La ventaja de este método es que los ids son una vista de avgDists:

 >>> ids.flags C_CONTIGUOUS : False F_CONTIGUOUS : False OWNDATA : False WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False 

(El ‘OWNDATA’ que es False indica que esto es una vista, no una copia)

Otra forma de hacer esto es algo como:

 (-avgDists).argsort()[:n] 

El problema es que la forma en que funciona es crear un negativo de cada elemento de la matriz:

 >>> (-avgDists) array([-1, -8, -6, -9, -4]) 

Y crea una copia para hacerlo:

 >>> (-avgDists_n).flags['OWNDATA'] True 

Así que si tiene tiempo para cada uno, incluso con este conjunto de datos muy pequeño:

 >>> import timeit >>> timeit.timeit('(-avgDists).argsort()[:3]', setup="from __main__ import avgDists") 4.2879798610229045 >>> timeit.timeit('avgDists.argsort()[::-1][:3]', setup="from __main__ import avgDists") 2.8372560259886086 

El método de visualización es sustancialmente más rápido.

Puede usar los comandos flip numpy.flipud() o numpy.fliplr() para obtener los índices en orden descendente después de ordenarlos usando el comando argsort . Eso es lo que suelo hacer.

En lugar de usar np.argsort , puede usar np.argpartition – si solo necesita los índices de los n elementos más altos / más bajos.

Eso no requiere ordenar toda la matriz, sino solo la parte que necesita, pero tenga en cuenta que el “orden dentro de su partición” no está definido, por lo que si bien proporciona los índices correctos, es posible que no estén ordenados correctamente:

 >>> avgDists = [1, 8, 6, 9, 4] >>> np.array(avgDists).argpartition(2)[:2] # indices of lowest 2 items array([0, 4], dtype=int64) >>> np.array(avgDists).argpartition(-2)[-2:] # indices of highest 2 items array([1, 3], dtype=int64) 

Podría crear una copia de la matriz y luego multiplicar cada elemento con -1.
Como efecto, antes los elementos más grandes se convertirían en los más pequeños.
Los índices de los n elementos más pequeños en la copia son los n elementos más grandes en el original.

Con tu ejemplo:

 avgDists = np.array([1, 8, 6, 9, 4]) 

Obtener índices de n valores máximos:

 ids = np.argpartition(avgDists, -n)[-n:] 

Ordenarlos en orden descendente:

 ids = ids[np.argsort(avgDists[ids])[::-1]] 

Obtener resultados (para n = 4):

 >>> avgDists[ids] array([9, 8, 6, 4]) 

Otra forma es usar solo un ‘-‘ en el argumento para argsort como en: “df [np.argsort (-df [:, 0])]”, siempre que df sea el dataframe y desee clasificarlo por el primero columna (representada por el número de columna ‘0’). Cambie el nombre de columna según corresponda. Por supuesto, la columna tiene que ser una numérica.

Una forma sencilla es tomar valores absolutos y agregar un signo negativo a cada elemento y luego hacer argsort.

 l=np.array([1,-1,2]) print(np.argsort((-np.abs(x)))) #[2,1,0]