Numpy: trouver les premier indice de la valeur rapide
Comment puis-je trouver l'index de la première occurrence d'un nombre dans un tableau Numpy?
La vitesse est importante pour moi. Je ne suis pas intéressé par les réponses ci-après parce qu'ils numériser l'ensemble du tableau et ne s'arrêtent pas quand ils trouver la première occurrence:
itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]
Note 1: aucune réponse de cette question semble pertinente Est-il un Numpy fonction pour renvoyer le premier indice d'un élément dans un tableau?
Note 2: à l'aide d'un C-compilé méthode est préférable à une boucle Python.
Vous devez vous connecter pour publier un commentaire.
Il y a une demande de fonctionnalité pour ce prévue pour Numpy 2.0.0: https://github.com/numpy/numpy/issues/2269
Bien qu'il est trop tard pour vous, mais pour une référence future:
À l'aide de numba (Un) est la façon la plus simple jusqu'à ce que numpy la met en œuvre. Si vous utilisez anaconda python de distribution, il devrait déjà être installé.
Le code sera compilé, donc il sera rapide.
et puis:
xrange
besoin d'être changé pourrange
.J'ai fait un benchmark de plusieurs méthodes:
argwhere
nonzero
comme dans la question.tostring()
comme dans @Rob Reilink la réponse deLa Python et Fortran code sont disponibles. J'ai sauté le compromis, comme la conversion d'une liste.
Les résultats sur l'échelle logarithmique. L'axe X est la position de l'aiguille (il faut plus de temps pour trouver si c'est plus bas dans le tableau); dernière valeur est une aiguille qui n'est pas dans le tableau. L'axe Y est le temps pour le trouver.
Le tableau avait 1 millions d'éléments et les tests ont été exécutés 100 fois. Des résultats encore fluctuer un peu, mais l'évolution qualitative est clair: Python et f2py arrêter au premier élément de sorte qu'ils des échelles différentes. Python est trop lent si l'aiguille n'est pas dans le premier 1%, alors que
f2py
est rapide (mais vous devez le compiler).Pour résumer, f2py est la solution la plus rapide, surtout si l'aiguille apparaît assez tôt.
Il n'est pas intégré dans ce qui est ennuyeux, mais c'est vraiment juste 2 minutes de travail. Ajouter cette dans un fichier appelé
search.f90
:Si vous êtes à la recherche d'autre chose que de
integer
, il suffit de changer le type. Ensuite compiler à l'aide de:après quoi vous pouvez le faire (à partir de Python):
f2py
de plus pour 1 élément que 10?Vous pouvez convertir une valeur de type boolean tableau à une chaîne Python à l'aide de
array.tostring()
, puis en utilisant la méthode find ():Ceci implique la copie de données, bien que, depuis le Python cordes doivent être immuable. Un avantage est que vous pouvez également effectuer une recherche, par exemple, un front montant par trouver
\x00\x01
En cas de tri des tableaux
np.searchsorted
œuvres.Je pense que vous avez frappé un problème où une méthode différente et certains a priori la connaissance de la matrice serait vraiment aider. Le genre de chose où vous avez un X probabilité de trouver votre réponse dans la première Y pour cent des données. Le fractionnement le problème avec l'espoir d'obtenir de la chance alors, faire en python avec une liste imbriquée de compréhension ou de quelque chose.
Écrire une fonction C pour ce faire, la force brute n'est pas trop dur à l'aide de ctypes soit.
Le code C j'ai bidouillé (index.c):
et le python:
et je reçois 92.
Envelopper le python dans une fonction appropriée et là vous allez.
La version C est beaucoup (~20x plus rapide de cette graine (attention je ne suis pas bon avec timeit)
@tal déjà présenté une
numba
fonction pour trouver le premier indice, mais qui ne fonctionne que pour les tableaux 1D. Avecnp.ndenumerate
vous pouvez également trouver le premier indice dans un arbitarly dimensions tableau:Exemple de cas:
Timings de montrer qu'il est semblable dans la performance de x solution:
array
avant de l'introduire dansnp.ndenumerate
, tels que votre axe de l'intérêt vient en premier.Autant que je sache seulement np.tout et np.tous les booléens les tableaux sont court-circuitées.
Dans votre cas, numpy doit passer par l'ensemble de la matrice, une fois pour créer la condition booléenne et une deuxième fois pour trouver les indices.
Ma recommandation dans ce cas serait d'utiliser cython. Je pense qu'il devrait être facile à régler un exemple pour ce cas, surtout si vous n'avez pas besoin de beaucoup de flexibilité pour les différents dtypes et de formes.
J'avais besoin pour mon travail donc je me suis enseigné Python Numpy et de l'interface C et écrit mon propre. http://pastebin.com/GtcXuLyd C'est uniquement pour les tableaux 1d, mais fonctionne pour la plupart des types de données (int, float, ou de chaînes de caractères) et les tests ont montré qu'il est encore environ 20 fois plus rapide que prévu de l'approche en pur Python-numpy.
Si votre liste est triés, vous pouvez obtenir très rapide de recherche de l'index avec le "coupent" paquet.
Il est O(log(n)) au lieu de O(n).
trouve x dans le tableau a, certainement plus rapide dans le triées cas que tout C-routine passe en revue tous les éléments premiers (assez longtemps listes).
Il est bon de savoir parfois.
>>> cond = "import numpy as np;a = np.arange(40)"
timeit("np.searchsorted(a, 39)", cond)
fonctionne pour 3.47867107391 secondes.timeit("bisect.bisect(a, 39)", cond2)
fonctionne pour 7.0661458969116 secondes. Il ressemble ànumpy.searchsorted
est mieux pour triés les tableaux (au moins pour ints).Comme une longue matlab utilisateur I ont été à la recherche d'une solution efficace à ce problème depuis un certain temps. Enfin, motivés par des discussions, une proposition dans ce fil j'ai essayé de venir avec une solution qui est de la mise en œuvre d'une API similaire à ce qui a été suggéré ici, l'appui pour l'instant, seuls tableaux 1D.
Que vous pouvez l'utiliser comme ceci
La condition opérateurs pris en charge sont: cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq. Pour l'efficacité de l'extension est écrit en c.
Vous trouver la source, de critères et d'autres détails ici:
https://pypi.python.org/pypi?name=py_find_1st&:action=afficher
pour l'utilisation dans notre équipe (anaconda sur linux et macos) j'ai fait un programme d'installation anaconda qui simplifie l'installation, vous pouvez l'utiliser comme décrit ici
https://anaconda.org/roebel/py_find_1st
Juste une note que si vous faites une séquence de recherches, le gain de performances de faire quelque chose d'intelligent comme la conversion de chaînes de caractères, peut-être perdu dans la boucle externe si la recherche de la dimension n'est pas assez grand. Voir comment la performance de l'itération find1 qui utilise la chaîne de conversion astuce proposée ci-dessus et find2 qui utilise argmax le long de l'intérieur de l'axe (en plus d'un ajustement pour assurer un non-match retourne -1)
sorties
Cela dit, écrit en C serait au moins un peu plus vite que l'autre de ces approches
comment à ce sujet
where(array==item)[0][0]
de la question...Ce problème peut être résolu dans le plus pur numpy par le traitement de la matrice en blocs:
Le tableau est transformé en morceau de la taille
step
. Lestep
plus l'étape est, le plus rapide est de traitement de remise à zéro-array (pire des cas). La plus petite, il est, au traitement plus rapide de tableau avec des non-zéro au début. Le truc est de commencer avec une petitestep
et de l'augmenter de façon exponentielle. En outre, il n'est pas nécessaire d'incrémenter au-dessus d'un certain seuil en raison des avantages limités.J'ai comparé la solution avec de la pure ndarary.différent de zéro et numba solution contre 10 millions de tableau de float.
Et les résultats sur ma machine:
Pur
ndarray.nonzero
est certain assouplissement. Le numba solution est environ 5 fois plus rapide pour le meilleur des cas. Il est environ 3 fois plus rapide dans le pire des cas.Vous pouvez convertir votre tableau dans un
list
et à l'utilisation c'estindex()
méthode:Autant que je suis au courant, c'est un C compilé méthode.
timeit()
sur un tableau de 10000 entiers -- la conversion d'une liste est environ 100 fois plus lent! J'avais oublié que les données sous-jacentes de la structure d'un tableau numpy est très différent à partir d'une liste..