web-dev-qa-db-fra.com

Est-il possible d'utiliser argsort dans l'ordre décroissant

Considérons le code suivant:

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

Cela me donne des indices des n plus petits éléments. Est-il possible d'utiliser cette même argsort en ordre décroissant pour obtenir les indices de n éléments les plus élevés?

120
shn

Si vous niez un tableau, les éléments les plus bas deviennent les éléments les plus élevés et inversement. Par conséquent, les indices des éléments n les plus élevés sont:

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

Une autre façon de raisonner à ce sujet, comme indiqué dans les commentaires , consiste à observer que les gros éléments arrivent last dans le fichier argsort. Donc, vous pouvez lire dans la queue de argsort pour trouver les n éléments les plus hauts: 

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

Les deux méthodes sont O (n log n) en complexité temporelle, car l'appel argsort est le terme dominant ici. Mais la seconde approche a un avantage intéressant: elle remplace la négation du tableau par O(n) par une tranche O(1). Si vous travaillez avec de petits tableaux à l'intérieur de boucles, vous pouvez obtenir des gains de performances en évitant cette négation, et si vous travaillez avec de grands tableaux, vous pouvez économiser sur l'utilisation de la mémoire car la négation crée une copie de tout le tableau. 

Notez que ces méthodes ne donnent pas toujours des résultats équivalents: si une implémentation de tri stable est demandée à argsort, par ex. en passant le mot clé argument kind='mergesort', alors la première stratégie préservera la stabilité du tri, mais la deuxième stratégie rompra la stabilité (c’est-à-dire que les positions des éléments égaux seront inversées). 

135
wim

Tout comme Python, [::-1] inverse le tableau renvoyé par argsort() et [:n] donne les n derniers éléments

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

L'avantage de cette méthode est que ids est une vue de avgDists:

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

(La valeur 'OWNDATA' étant False, il s'agit d'une vue, pas d'une copie.) 

Une autre façon de faire est quelque chose comme:

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

Le problème est que cela fonctionne de manière à créer un négatif de chaque élément du tableau:

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

Et crée une copie pour le faire:

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

Donc, si vous chronométrez chacun, même avec ce très petit ensemble de données:

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

La méthode de visualisation est considérablement plus rapide

62
dawg

Vous pouvez utiliser les commandes Flip numpy.flipud() ou numpy.fliplr() pour obtenir les index dans l'ordre décroissant après le tri à l'aide de la commande argsort. Cest ce que je fais habituellement.

4
Kanmani

Au lieu d'utiliser np.argsort, vous pouvez utiliser np.argpartition - si vous avez seulement besoin des index des n éléments les plus bas/les plus hauts. 

Cela ne nécessite pas de trier tout le tableau, mais seulement la partie dont vous avez besoin, mais notez que "l'ordre dans votre partition" n'est pas défini, ainsi, même s'il donne les index corrects, il se peut qu'il ne soit pas correctement ordonné:

>>> 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)
3
MSeifert

Vous pouvez créer une copie du tableau, puis multiplier chaque élément par -1.
En conséquence, les plus gros éléments avant deviendraient les plus petits.
Les indeces des n plus petits éléments de la copie sont les n plus grands éléments de l'original.

2
MentholBonbon

Avec votre exemple: 

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

Obtenir des index de n valeurs maximales:

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

Triez-les par ordre décroissant:

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

Obtenir des résultats (pour n = 4):

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

Comme @Kanmani l'a laissé entendre, une implémentation plus facile à interpréter peut utiliser numpy.flip, comme suit:

import numpy as np

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

En utilisant le modèle de visiteur plutôt que les fonctions membres, il est plus facile de lire l'ordre des opérations.

1
Adam Erickson

Une autre méthode consiste à utiliser uniquement un '-' dans l'argument pour argsort, comme dans: "df [np.argsort (-df [:, 0])]", à condition que df soit le cadre de données et que vous souhaitiez le trier par colonne (représentée par le numéro de colonne '0'). Changez le nom de la colonne comme il convient. Bien sûr, la colonne doit être numérique.

0
Biswajit Ghoshal

Un moyen simple consiste à prendre des valeurs absolues et à ajouter un signe négatif à chaque élément, puis à argumenter.

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