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