Ordenar matrices en NumPy por columna
¿Cómo ordeno una matriz NumPy por su enésima columna?
Por ejemplo, dado:
a = array([[9, 2, 3],
[4, 5, 6],
[7, 0, 5]])
Quiero ordenar las filas a
por la segunda columna para obtener:
array([[7, 0, 5],
[9, 2, 3],
[4, 5, 6]])
Para ordenar por la segunda columna de a
:
a[a[:, 1].argsort()]
La respuesta de @steve es en realidad la forma más elegante de hacerlo.
Para conocer la forma "correcta", consulte el argumento de la palabra clave de orden de numpy.ndarray.sort
Sin embargo, necesitarás ver tu matriz como una matriz con campos (una matriz estructurada).
La forma "correcta" es bastante fea si inicialmente no definiste tu matriz con campos...
Como ejemplo rápido, para ordenarlo 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 ordenarlo 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's realmente es la forma más elegante de hacerlo, hasta donde yo sé...
La única ventaja de este método es que el argumento "orden" es una lista de campos para ordenar la búsqueda. Por ejemplo, puede ordenar por la segunda columna, luego por la tercera columna y luego por la primera columna proporcionando orden=['f1','f2','f0'].
Puede ordenar varias columnas según el método de Steve Tjoa utilizando una clasificación estable como mergesort y ordenando los índices desde las columnas menos significativas hasta 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.
En caso de que alguien quiera utilizar la clasificación en una parte crítica de sus programas, aquí hay una comparación de rendimiento 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...