Numpy argsort: ¿qué está haciendo?

123

¿Por qué numpy está dando este resultado?

x = numpy.array([1.48,1.41,0.0,0.1])
print x.argsort()

>[2 3 1 0]

cuando esperaría que hiciera esto:

[3 2 0 1]

Claramente, mi comprensión de la función es deficiente.

usuario1276273
fuente
6
¿Por qué pensaste [3 2 0 1]que habría sido la respuesta correcta?
zwol
9
Acabo de tener una comprensión invertida de la salida. Es decir, si toma el primer elemento de x, debería estar en la posición 3 de una matriz ordenada y así sucesivamente.
user1276273
26
su forma de pensar tiene mucho sentido, tenía exactamente la misma pregunta
adrienlucca.wordpress.com
2
[3 2 0 1]: se trata de clasificar los valores, no se obtienen los índices reales.
Lahiru Karunaratne
Solo para recordar que la salida indica ubicaciones en la matriz original mientras piensa en la matriz ordenada. Eso significa que la salida [0] es el índice donde se ubica el elemento más pequeño en la matriz de entrada original y la salida [-1] para el elemento más grande.
lincr

Respuestas:

144

Según la documentación

Devuelve los índices que ordenarían una matriz.

  • 2es el índice de 0.0.
  • 3es el índice de 0.1.
  • 1es el índice de 1.41.
  • 0es el índice de 1.48.
falsetru
fuente
12
a = x.argsort(), imprimir x[a], obtendremosarray([ 0. , 0.1 , 1.41, 1.48])
Belter
39

[2, 3, 1, 0] indica que el elemento más pequeño está en el índice 2, el siguiente más pequeño en el índice 3, luego el índice 1, luego el índice 0.

Hay varias formas de obtener el resultado que busca:

import numpy as np
import scipy.stats as stats

def using_indexed_assignment(x):
    "https://stackoverflow.com/a/5284703/190597 (Sven Marnach)"
    result = np.empty(len(x), dtype=int)
    temp = x.argsort()
    result[temp] = np.arange(len(x))
    return result

def using_rankdata(x):
    return stats.rankdata(x)-1

def using_argsort_twice(x):
    "https://stackoverflow.com/a/6266510/190597 (k.rooijers)"
    return np.argsort(np.argsort(x))

def using_digitize(x):
    unique_vals, index = np.unique(x, return_inverse=True)
    return np.digitize(x, bins=unique_vals) - 1

Por ejemplo,

In [72]: x = np.array([1.48,1.41,0.0,0.1])

In [73]: using_indexed_assignment(x)
Out[73]: array([3, 2, 0, 1])

Esto verifica que todos produzcan el mismo resultado:

x = np.random.random(10**5)
expected = using_indexed_assignment(x)
for func in (using_argsort_twice, using_digitize, using_rankdata):
    assert np.allclose(expected, func(x))

Estos %timeitpuntos de referencia de IPython sugieren que para arreglos grandes using_indexed_assignmentes el más rápido:

In [50]: x = np.random.random(10**5)
In [66]: %timeit using_indexed_assignment(x)
100 loops, best of 3: 9.32 ms per loop

In [70]: %timeit using_rankdata(x)
100 loops, best of 3: 10.6 ms per loop

In [56]: %timeit using_argsort_twice(x)
100 loops, best of 3: 16.2 ms per loop

In [59]: %timeit using_digitize(x)
10 loops, best of 3: 27 ms per loop

Para arreglos pequeños, using_argsort_twicepuede ser más rápido:

In [78]: x = np.random.random(10**2)

In [81]: %timeit using_argsort_twice(x)
100000 loops, best of 3: 3.45 µs per loop

In [79]: %timeit using_indexed_assignment(x)
100000 loops, best of 3: 4.78 µs per loop

In [80]: %timeit using_rankdata(x)
100000 loops, best of 3: 19 µs per loop

In [82]: %timeit using_digitize(x)
10000 loops, best of 3: 26.2 µs per loop

Tenga en cuenta también que stats.rankdatale da más control sobre cómo manejar elementos de igual valor.

unutbu
fuente
1
¿Puede agregar alguna explicación sobre por qué la aplicación de argsort () dos veces nos da el rango?
Phani
1
@Phani: argsortdevuelve los índices de la matriz ordenada. El índice de los índices ordenados es el rango. Esto es lo que argsortvuelve la segunda llamada a .
Unutbu
2
El primer argsort devuelve una permutación (que si se aplica a los datos lo ordenaría). Cuando se aplica argsort a (esta o cualquier) permutación, devuelve la permutación inversa (que si las 2 permutaciones se aplican entre sí en cualquier orden, el resultado es la Identidad). La segunda permutación, si se aplica a una matriz de datos ordenados, produciría la matriz de datos sin clasificar, es decir, es el rango.
Alex C
1
Alucinado. ¡Finalmente lo entendí! Devuelve una matriz cuyo contenido son los índices de la matriz original en un orden ordenado.
Jose A
3

Como dice la documentaciónargsort :

Devuelve los índices que ordenarían una matriz.

Eso significa que el primer elemento del argsort es el índice del elemento que debe ordenarse primero, el segundo elemento es el índice del elemento que debe ser el segundo, etc.

Lo que parece querer es el orden de clasificación de los valores, que es lo que proporciona scipy.stats.rankdata. Tenga en cuenta que debe pensar en lo que debería suceder si hay empates en las filas.

BrenBarn
fuente
3

numpy.argsort (a, axis = -1, kind = 'quicksort', order = None)

Devuelve los índices que ordenarían una matriz.

Realice una ordenación indirecta a lo largo del eje dado utilizando el algoritmo especificado por la palabra clave kind. Devuelve una matriz de índices de la misma forma que los datos del índice a lo largo del eje dado en orden ordenado.

Considere un ejemplo en Python, que tiene una lista de valores como

listExample  = [0 , 2, 2456,  2000, 5000, 0, 1]

Ahora usamos la función argsort:

import numpy as np
list(np.argsort(listExample))

La salida será

[0, 5, 6, 1, 3, 2, 4]

Esta es la lista de índices de valores en listEjemplo, si asigna estos índices a los valores respectivos, obtendremos el resultado de la siguiente manera:

[0, 0, 1, 2, 2000, 2456, 5000]

(Encuentro esta función muy útil en muchos lugares, por ejemplo, si desea ordenar la lista / matriz pero no desea usar la función list.sort () (es decir, sin cambiar el orden de los valores reales en la lista) puede usar esto función.)

Para obtener más detalles, consulte este enlace: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html

Yogesh
fuente
1

entrada:
importar numpy como np
x = np.array ([1.48,1.41,0.0,0.1])
x.argsort (). argsort ()

salida:
matriz ([3, 2, 0, 1])

JMpony
fuente
1
Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo a la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código.
peacetype
0

Primero, se ordenó la matriz. Luego genere una matriz con el índice inicial de la matriz.

Rodrigo Saraguro
fuente
0

np.argsort devuelve el índice de la matriz ordenada dada por el 'tipo' (que especifica el tipo de algoritmo de ordenación). Sin embargo, cuando se usa una lista con np.argmax, devuelve el índice del elemento más grande de la lista. Mientras que, np.sort, ordena la matriz dada, list.

vivek
fuente
0

Solo quiero contrastar directamente la comprensión original del OP con la implementación real con código.

numpy.argsort se define de modo que para matrices 1D:

x[x.argsort()] == numpy.sort(x) # this will be an array of True's

El OP originalmente pensó que estaba definido de tal manera que para matrices 1D:

x == numpy.sort(x)[x.argsort()] # this will not be True

Nota: Este código no funciona en el caso general (solo funciona para 1D), esta respuesta es puramente ilustrativa.

Cazador múltiple
fuente
x[x.argsort()]no es necesariamente lo mismo que np.sort(x). De hecho, ni siquiera tiene necesariamente la misma forma. Pruebe esto con una matriz 2D. Esto solo funciona con matrices 1D.
Nathan
Siento que eso es innecesariamente pedante. La pregunta es sobre matrices 1D. Esto pretende ser una forma de comprender cuál era la diferencia, en lugar de utilizar un código literal. Además, cuando tiene una matriz 2D, ni siquiera está claro qué tipo de clasificación desea. ¿Quieres una clasificación global? Si no es así, ¿qué eje debería ordenarse? Independientemente, agregué un descargo de responsabilidad.
Multihunter
0

Devuelve índices de acuerdo con los índices de matriz dados [1.48,1.41,0.0,0.1], eso significa: 0.0es el primer elemento, en index [2]. 0.1es el segundo elemento, en el índice [3]. 1.41es el tercer elemento, en el índice [1]. 1.48es el cuarto elemento, en el índice [0]. Salida:

[2,3,1,0]
nucsit026
fuente