J'ai un tableau numpy comme celui-ci: [1 2 2 0 0 1 3 5]
Est-il possible d'obtenir l'index des éléments sous forme de tableau 2D? Par exemple, la réponse pour l'entrée ci-dessus serait[[3 4], [0 5], [1 2], [6], [], [7]]
Actuellement, je dois boucler les différentes valeurs et appeler numpy.where(input == i)
chaque valeur, qui a des performances terribles avec une entrée assez grande.
python
numpy
numpy-ndarray
Frederico Schardong
la source
la source
np.argsort([1, 2, 2, 0, 0, 1, 3, 5])
donnearray([3, 4, 0, 5, 1, 2, 6, 7], dtype=int64)
. alors vous pouvez simplement comparer les éléments suivants.Réponses:
Voici une approche O (max (x) + len (x)) utilisant
scipy.sparse
:Cela fonctionne en créant une matrice clairsemée avec des entrées aux positions (x [0], 0), (x [1], 1), ...
CSC
format (colonne creuse compressée) c'est assez simple. La matrice est ensuite convertie auLIL
format (liste liée). Ce format stocke les indices de colonne pour chaque ligne sous forme de liste dans sonrows
attribut, donc tout ce que nous devons faire est de prendre cela et de le convertir en liste.Notez que pour les petites baies, les
argsort
solutions basées sont probablement plus rapides, mais à une taille pas incroyablement grande, cela se croisera.ÉDITER:
argsort
basée sur unenumpy
seule solution:Si l'ordre des indices au sein des groupes n'a pas d'importance, vous pouvez également essayer
argpartition
(cela ne fait aucune différence dans ce petit exemple mais ce n'est pas garanti en général):ÉDITER:
@Divakar déconseille l'utilisation de
np.split
. Au lieu de cela, une boucle est probablement plus rapide:Ou vous pouvez utiliser le tout nouvel opérateur de morse (Python3.8 +):
MODIFIER (MODIFIÉ):
(Pas pur numpy): Comme alternative à numba (voir le post de @ senderle), nous pouvons également utiliser pythran.
Compiler avec
pythran -O3 <filename.py>
Ici
numba
gagne par une moustache en termes de performances:Trucs plus anciens:
Timings vs numba (ancien)
la source
np.split
.Une option potentielle en fonction de la taille de vos données consiste à simplement abandonner
numpy
et utilisercollections.defaultdict
:Ensuite, vous vous retrouvez avec un dictionnaire de
{value1: [index1, index2, ...], value2: [index3, index4, ...]}
. L'échelle de temps est assez proche de la linéarité avec la taille du tableau, donc 10 000 000 prennent environ 2,7 secondes sur ma machine, ce qui semble assez raisonnable.la source
Bien que la demande concerne une
numpy
solution, j'ai décidé de voir s'il existe unenumba
solution intéressante . Et en effet il y en a! Voici une approche qui représente la liste partitionnée sous la forme d'un tableau déchiqueté stocké dans un seul tampon préalloué. Cela s'inspire de l'argsort
approche proposée par Paul Panzer . (Pour une version plus ancienne qui ne fonctionnait pas aussi bien, mais qui était plus simple, voir ci-dessous.)Cela traite une liste de dix millions d'éléments en 75 ms, ce qui représente une accélération de près de 50 fois par rapport à une version basée sur une liste écrite en pur Python.
Pour une version plus lente mais un peu plus lisible, voici ce que j'avais avant, basé sur un support expérimental récemment ajouté pour les "listes typées" de taille dynamique, qui nous permettent de remplir chaque bac de manière désordonnée beaucoup plus rapidement.
Cela lutte un peu avec
numba
le moteur d'inférence de type, et je suis sûr qu'il existe une meilleure façon de gérer cette partie. Cela s'avère également être presque 10 fois plus lent que ce qui précède.Je les ai testés par rapport aux éléments suivants:
Je les ai également testés contre une version cython précompilée similaire à
enum_bins_numba_buffer
(décrite en détail ci-dessous).Sur une liste de dix millions d'ints aléatoires (
ints = np.random.randint(0, 100, 10000000)
) j'obtiens les résultats suivants:Impressionnant, cette façon de travailler avec
numba
surpasse unecython
version de la même fonction, même avec la vérification des limites désactivée. Je n'ai pas encore assez de connaissancespythran
pour tester cette approche en l'utilisant, mais je serais intéressé de voir une comparaison. Il semble probable sur la base de cette accélération que lepythran
version pourrait également être un peu plus rapide avec cette approche.Voici la
cython
version pour référence, avec quelques instructions de construction. Une fois que vous avezcython
installé, vous aurez besoin d'unsetup.py
fichier simple comme celui-ci:Et le module cython,
enum_bins_cython.pyx
:Avec ces deux fichiers dans votre répertoire de travail, exécutez cette commande:
Vous pouvez ensuite importer la fonction à l'aide de
from enum_bins_cython import enum_bins_cython
.la source
Voici une façon vraiment vraiment bizarre de faire cela, c'est terrible, mais je l'ai trouvé trop drôle pour ne pas le partager - et tout
numpy
!EDIT: c'est la meilleure méthode que j'ai pu trouver le long de ce chemin. C'est toujours 10 fois plus lent que la solution de @PaulPanzer
argsort
:la source
Vous pouvez le faire en créant un dictionnaire de nombres, les clés seraient les nombres et les valeurs devraient être les indices que le nombre a vus, c'est l'un des moyens les plus rapides de le faire, vous pouvez voir le code ci-dessous:
la source
Pseudocode:
obtenir le "nombre de tableaux 1d dans le tableau 2d", en soustrayant la valeur minimale de votre tableau numpy de la valeur maximale, puis plus un. Dans votre cas, ce sera 5-0 + 1 = 6
initialiser un tableau 2D avec le nombre de tableaux 1D qu'il contient. Dans votre cas, initialisez un tableau 2D avec 6 tableaux 1D. Chaque tableau 1d correspond à un élément unique de votre tableau numpy, par exemple, le premier tableau 1d correspondra à '0', le second tableau 1d correspondra à '1', ...
boucle dans votre tableau numpy, placez l'index de l'élément dans le tableau 1d correspondant droit. Dans votre cas, l'index du premier élément de votre tableau numpy sera placé dans le deuxième tableau 1d, l'indice du deuxième élément de votre tableau numpy sera mis dans le troisième tableau 1d, ....
Ce pseudocode prendra un temps linéaire pour s'exécuter car il dépend de la longueur de votre tableau numpy.
la source
Cela vous donne exactement ce que vous voulez et prendrait environ 2,5 secondes pour 10 000 000 sur ma machine:
la source
Donc, étant donné une liste d'éléments, vous voulez faire des paires (élément, index). En temps linéaire, cela pourrait se faire comme:
Cela devrait prendre du temps O (n). Je ne peux pas penser à une solution plus rapide pour l'instant, mais je mettrai à jour ici si je le fais.
la source