Ordenando matrices en NumPy por columna

¿Cómo puedo ordenar una matriz en NumPy por la columna nth?

Por ejemplo,

a = array([[9, 2, 3], [4, 5, 6], [7, 0, 5]]) 

Me gustaría ordenar las filas por la segunda columna, de manera que vuelva:

 array([[7, 0, 5], [9, 2, 3], [4, 5, 6]]) 

@steve ‘s es en realidad la forma más elegante de hacerlo.

Para la forma “correcta”, vea el argumento de la palabra clave de orden numpy.ndarray.sort

Sin embargo, deberá ver su matriz como una matriz con campos (una matriz estructurada).

La forma “correcta” es bastante fea si inicialmente no definió su matriz con campos …

Como ejemplo rápido, para ordenar y devolver una copia:

 In [1]: import numpy as np In [2]: a = np.array([[1,2,3],[4,5,6],[0,0,1]]) In [3]: np.sort(a.view('i8,i8,i8'), order=['f1'], axis=0).view(np.int) Out[3]: array([[0, 0, 1], [1, 2, 3], [4, 5, 6]]) 

Para ordenar en el lugar:

 In [6]: a.view('i8,i8,i8').sort(order=['f1'], axis=0) #<-- returns None In [7]: a Out[7]: array([[0, 0, 1], [1, 2, 3], [4, 5, 6]]) 

@ Steve realmente es la forma más elegante de hacerlo, que yo sepa ...

La única ventaja de este método es que el argumento "orden" es una lista de los campos para ordenar la búsqueda. Por ejemplo, puede ordenar por la segunda columna, luego la tercera columna, luego la primera columna proporcionando el orden = ['f1', 'f2', 'f0'].

Supongo que esto funciona: a[a[:,1].argsort()]

Esto indica la segunda columna de a y la clasifica en función de ella en consecuencia.

Puede ordenar en múltiples columnas según el método de Steve Tjoa usando una ordenación estable como mergesort y clasificando los índices de las columnas menos significativas a las más significativas:

 a = a[a[:,2].argsort()] # First sort doesn't need to be stable. a = a[a[:,1].argsort(kind='mergesort')] a = a[a[:,0].argsort(kind='mergesort')] 

Esto ordena por columna 0, luego 1, luego 2.

Desde la wiki de documentación de Python , creo que puedes hacer:

 a = ([[1, 2, 3], [4, 5, 6], [0, 0, 1]]); a = sorted(a, key=lambda a_entry: a_entry[1]) print a 

La salida es:

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

En caso de que alguien quiera usar la clasificación en una parte crítica de sus progtwigs, aquí hay una comparación de desempeño para las diferentes propuestas:

 import numpy as np table = np.random.rand(5000, 10) %timeit table.view('f8,f8,f8,f8,f8,f8,f8,f8,f8,f8').sort(order=['f9'], axis=0) 1000 loops, best of 3: 1.88 ms per loop %timeit table[table[:,9].argsort()] 10000 loops, best of 3: 180 µs per loop import pandas as pd df = pd.DataFrame(table) %timeit df.sort_values(9, ascending=True) 1000 loops, best of 3: 400 µs per loop 

Entonces, parece que la indexación con argsort es el método más rápido hasta ahora …

De la lista de correo de NumPy , aquí hay otra solución:

 >>> a array([[1, 2], [0, 0], [1, 0], [0, 2], [2, 1], [1, 0], [1, 0], [0, 0], [1, 0], [2, 2]]) >>> a[np.lexsort(np.fliplr(a).T)] array([[0, 0], [0, 0], [0, 2], [1, 0], [1, 0], [1, 0], [1, 0], [1, 2], [2, 1], [2, 2]]) 

Tuve un problema similar.

Mi problema:

Quiero calcular una SVD y necesito ordenar mis valores propios en orden descendente. Pero quiero mantener el mapeo entre los valores propios y los vectores propios. Mis valores propios estaban en la primera fila y el vector propio correspondiente debajo de ella en la misma columna.

Así que quiero ordenar una matriz bidimensional por columnas en la primera fila en orden descendente.

Mi solución

 a = a[::, a[0,].argsort()[::-1]] 

Entonces, ¿cómo funciona esto?

a[0,] es solo la primera fila por la que quiero ordenar.

Ahora uso argsort para obtener el orden de los índices.

Utilizo [::-1] porque necesito orden descendente.

Por último, uso a[::, ...] para obtener una vista con las columnas en el orden correcto.

Un ejemplo lexsort un poco más complicado: descendiendo en la 1ª columna, subiendo en segundo lugar en la 2ª. Los trucos con lexsort son que se lexsort en filas (por lo tanto, la .T ), y le da prioridad a la última.

 In [120]: b=np.array([[1,2,1],[3,1,2],[1,1,3],[2,3,4],[3,2,5],[2,1,6]]) In [121]: b Out[121]: array([[1, 2, 1], [3, 1, 2], [1, 1, 3], [2, 3, 4], [3, 2, 5], [2, 1, 6]]) In [122]: b[np.lexsort(([1,-1]*b[:,[1,0]]).T)] Out[122]: array([[3, 1, 2], [3, 2, 5], [2, 1, 6], [2, 3, 4], [1, 1, 3], [1, 2, 1]]) 

Aquí hay otra solución considerando todas las columnas (forma más compacta de la respuesta de JJ );

 ar=np.array([[0, 0, 0, 1], [1, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 1], [0, 0, 1, 0], [1, 1, 0, 0]]) 

Ordenar con lexsort,

 ar[np.lexsort(([ar[:, i] for i in range(ar.shape[1]-1, -1, -1)]))] 

Salida:

 array([[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 1], [1, 0, 1, 0], [1, 1, 0, 0]])