J'ai un tableau de nombres et j'aimerais créer un autre tableau qui représente le rang de chaque élément dans le premier tableau. J'utilise Python et NumPy.
Par exemple:
array = [4,2,7,1]
ranks = [2,1,3,0]
Voici la meilleure méthode que j'ai trouvée:
array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]
Existe-t-il des méthodes meilleures / plus rapides qui évitent de trier le tableau deux fois?
ranks = temp.argsort()
.Réponses:
Utilisez le tranchage sur le côté gauche dans la dernière étape:
Cela évite de trier deux fois en inversant la permutation lors de la dernière étape.
la source
Utilisez argsort deux fois, d'abord pour obtenir l'ordre du tableau, puis pour obtenir le classement:
Lorsque vous traitez avec des tableaux 2D (ou de dimension supérieure), assurez-vous de passer un argument d'axe à argsort pour passer le bon axe.
la source
[4,2,7,1,1]
), la sortie classera ces nombres en fonction de leur position dans le tableau ([3,2,4,0,1]
)argsort
.array = np.random.rand(10)
devrait êtrearray = np.random.rand(n)
.Cette question date de quelques années et la réponse acceptée est excellente, mais je pense que ce qui suit mérite d'être mentionné. Si cela ne vous dérange pas de la dépendance
scipy
, vous pouvez utiliserscipy.stats.rankdata
:Une fonctionnalité intéressante de
rankdata
est que l'method
argument offre plusieurs options pour gérer les liens. Par exemple, il y a trois occurrences de 20 et deux occurrences de 40 dansb
:La valeur par défaut attribue le rang moyen aux valeurs liées:
method='ordinal'
attribue des rangs consécutifs:method='min'
affecte le rang minimum des valeurs liées à toutes les valeurs liées:Voir la docstring pour plus d'options.
la source
rankdata
semble utiliser le même mécanisme que la réponse acceptée pour générer le classement initial en interne.J'ai essayé d'étendre les deux solutions pour les tableaux A de plus d'une dimension, en supposant que vous traitez votre tableau ligne par ligne (axe = 1).
J'ai étendu le premier code avec une boucle sur les lignes; il peut probablement être amélioré
Et le second, suivant la suggestion de k.rooijers, devient:
J'ai généré au hasard 400 tableaux de forme (1000, 100); le premier code prenait environ 7,5, le second 3,8.
la source
Pour une version vectorisée d'un rang moyen, voir ci-dessous. J'adore np.unique, cela élargit vraiment la portée de ce que le code peut et ne peut pas être efficacement vectorisé. En plus d'éviter les boucles for python, cette approche évite également la double boucle implicite sur «a».
la source
Outre l'élégance et la brièveté des solutions, il y a aussi la question de la performance. Voici un petit repère:
la source
rankdata(l, method='ordinal') - 1
.Utilisez argsort () deux fois pour le faire:
la source
J'ai essayé les méthodes ci-dessus, mais j'ai échoué car j'avais beaucoup de zeores. Oui, même avec des éléments flottants, les doublons peuvent être importants.
J'ai donc écrit une solution 1D modifiée en ajoutant une étape de vérification des liens:
Je pense que c'est aussi efficace que possible.
la source
J'ai aimé la méthode de k.rooijers, mais comme l'a écrit rcoup, les nombres répétés sont classés en fonction de la position du tableau. Ce n'était pas bon pour moi, j'ai donc modifié la version pour post-traiter les rangs et fusionner tous les nombres répétés en un rang moyen combiné:
J'espère que cela pourrait aussi aider les autres, j'ai essayé de trouver une autre solution à cela, mais je n'ai pas trouvé de solution ...
la source
argsort et slice sont des opérations de symétrie.
essayez slice deux fois au lieu d'argsort deux fois. puisque slice est plus rapide que argsort
la source
Version plus générale de l'une des réponses:
Voir Comment utiliser numpy.argsort () comme index dans plus de 2 dimensions? pour généraliser à plus de dims.
la source