web-dev-qa-db-fra.com

Tri des tableaux dans NumPy par colonne

Comment puis-je trier un tableau dans NumPy par la nième colonne?

Par exemple,

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

Je voudrais trier les lignes par la deuxième colonne, de sorte que je revienne:

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

@steve est en fait le moyen le plus élégant de le faire.

Pour la méthode "correcte", voir l'argument de mot-clé d'ordre de numpy.ndarray.sort

Cependant, vous devez afficher votre tableau sous forme de tableau avec des champs (un tableau structuré).

La méthode "correcte" est assez moche si vous n'avez pas défini initialement votre tableau avec des champs ...

À titre d’exemple rapide, pour trier et renvoyer une copie:

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]])

Pour le trier sur place:

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 est vraiment le moyen le plus élégant de le faire, autant que je sache ... 

Le seul avantage de cette méthode est que l'argument "order" est une liste des champs dans lesquels la recherche est ordonnée. Par exemple, vous pouvez trier par la deuxième colonne, puis la troisième colonne, puis la première colonne en fournissant order = ['f1', 'f2', 'f0'].

104
Joe Kington

Je suppose que cela fonctionne: a[a[:,1].argsort()]

Ceci indique la deuxième colonne de a et triez-la en conséquence.

551
Steve Tjoa

Vous pouvez trier sur plusieurs colonnes selon la méthode de Steve Tjoa en utilisant un tri stable tel que mergesort et en triant les index des colonnes les moins importantes aux plus significatives:

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')]

Cela trie par colonne 0, puis 1, puis 2.

22
J.J

Depuis le wiki de la documentation Python , je pense que vous pouvez faire:

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

La sortie est:

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

À partir de la liste de diffusion NumPy , voici une autre solution:

>>> 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]])
14
fgregg

Si quelqu'un souhaite utiliser le tri dans une partie critique de ses programmes, voici une comparaison des performances pour les différentes propositions:

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

Il semble donc que l’indexation avec argsort soit la méthode la plus rapide jusqu’à présent ...

13
MonkeyButter

J'avais un problème similaire.

Mon problème:

Je veux calculer un SVD et dois trier mes valeurs propres par ordre décroissant. Mais je veux conserver la correspondance entre les valeurs propres et les vecteurs propres . Mes valeurs propres se trouvaient dans la première ligne et le vecteur propre correspondant en dessous dans la même colonne.

Je veux donc trier un tableau à deux dimensions par colonne dans l'ordre décroissant de la première ligne.

Ma solution

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

Donc comment ça fonctionne?

a[0,] est juste la première ligne que je veux trier.

Maintenant, j'utilise argsort pour obtenir l'ordre des indices.

J'utilise [::-1] parce que j'ai besoin d'un ordre décroissant.

Enfin, j'utilise a[::, ...] pour obtenir une vue avec les colonnes dans le bon ordre.

3
xuma202

Exemple lexsort un peu plus compliqué - décroissant sur la 1ère colonne, secondairement croissant sur la 2ème. Les astuces avec lexsort consistent à trier les lignes (d'où le .T) et à donner la priorité à la dernière.

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]])
1
hpaulj

Voici une autre solution en considérant toutes colonnes (moyen plus compact de la réponse de J.J );

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]])

Trier avec lexsort,

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

Sortie:

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]])
0
Sefa