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 suivantes car elles analysent l'ensemble du tableau et ne s'arrêtent pas quand elles trouvent la première occurrence:
itemindex = numpy.where(array==item)[0][0]
nonzero(array == item)[0][0]
Note 1: aucune des réponses à cette question ne semble pertinente. Existe-t-il une fonction Numpy pour renvoyer le premier index de quelque chose dans un tableau?
Note 2: l'utilisation d'une méthode compilée en C est préférable à une boucle Python.
Bien qu'il soit bien trop tard pour vous, mais pour référence future: utiliser numba ( 1 ) est le moyen le plus simple jusqu'à ce que numpy l'implémente. Si vous utilisez la distribution anaconda python, elle devrait déjà être installée. Le code sera compilé donc il sera rapide.
puis:
la source
xrange
doivent être modifiés pourrange
.enumerate
, comme dansfor i, v in enumerate(vec):
;if v == item: return i
. (Ce n'est pas une bonne idée en Python <= 2.7, oùenumerate
crée une liste plutôt qu'un itérateur de base.)J'ai fait une référence pour plusieurs méthodes:
argwhere
nonzero
comme dans la question.tostring()
comme dans la réponse de @Rob ReilinkLes codes Python et Fortran sont disponibles. J'ai sauté les moins prometteurs comme la conversion en liste.
Les résultats sur une échelle logarithmique. L'axe X est la position de l'aiguille (il faut plus de temps pour savoir si elle est plus loin dans le tableau); la dernière valeur est une aiguille qui n'est pas dans le tableau. L'axe Y est le temps de le trouver.
Le tableau contenait 1 million d'éléments et les tests ont été exécutés 100 fois. Les résultats fluctuent encore un peu, mais la tendance qualitative est claire: Python et f2py s'arrêtent au premier élément, ils évoluent donc différemment. Python devient trop lent si l'aiguille n'est pas dans le premier 1%, alors qu'il
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.
Ce n'est pas intégré ce qui est ennuyeux, mais ce n'est vraiment que 2 minutes de travail. Ajoutez ceci à un fichier appelé
search.f90
:Si vous recherchez autre chose que
integer
, changez simplement le type. Puis compilez en utilisant:après quoi vous pouvez faire (à partir de Python):
la source
f2py
plus lent pour 1 élément que 10?Vous pouvez convertir un tableau booléen en chaîne Python en utilisant
array.tostring()
puis en utilisant la méthode find ():Cela implique cependant de copier les données, car les chaînes Python doivent être immuables. Un avantage est que vous pouvez également rechercher par exemple un front montant en trouvant
\x00\x01
la source
Dans le cas de tableaux triés
np.searchsorted
fonctionne.la source
Je pense que vous avez rencontré un problème où une méthode différente et une connaissance a priori du tableau aideraient vraiment. Le genre de chose où vous avez une probabilité X de trouver votre réponse dans les Y premiers pour cent des données. Le fractionnement du problème avec l'espoir d'avoir de la chance, puis de le faire en python avec une compréhension de liste imbriquée ou quelque chose.
Ecrire une fonction C pour faire cette force brute n'est pas non plus trop difficile en utilisant des ctypes .
Le code C que j'ai piraté ensemble (index.c):
et le python:
et j'en ai 92.
Enveloppez le python dans une fonction appropriée et le tour est joué.
La version C est beaucoup (~ 20x) plus rapide pour cette graine (attention je ne suis pas bon avec timeit)
la source
@tal a déjà présenté une
numba
fonction pour trouver le premier index mais qui ne fonctionne que pour les tableaux 1D. Avecnp.ndenumerate
vous pouvez également trouver le premier index dans un tableau de dimensions arbitraires:Exemple de cas:
Les délais montrent que ses performances sont similaires à celles de la solution tals :
la source
array
avant de l'introduirenp.ndenumerate
, de sorte que votre axe d'intérêt passe en premier.np.argwhere
) à 717ns (votre solution), les deux pour un tableau de forme(3000000, 12)
).Si votre liste est triée , vous pouvez effectuer une recherche d'index très rapide avec le package 'bisect'. C'est O (log (n)) au lieu de O (n).
trouve x dans le tableau a, nettement plus rapide dans le cas trié que n'importe quelle routine C passant par tous les premiers éléments (pour des listes suffisamment longues).
C'est bon à savoir parfois.
la source
>>> cond = "import numpy as np;a = np.arange(40)"
timeit("np.searchsorted(a, 39)", cond)
fonctionne pendant 3,47867107391 secondes.timeit("bisect.bisect(a, 39)", cond2)
fonctionne pendant 7,0661458969116 secondes. Il semble quenumpy.searchsorted
c'est mieux pour les tableaux triés (au moins pour les entiers).Autant que je sache, seuls np.any et np.all sur des tableaux booléens sont court-circuités.
Dans votre cas, numpy doit parcourir le tableau entier deux fois, une fois pour créer la condition booléenne et une seconde fois pour trouver les indices.
Ma recommandation dans ce cas serait d'utiliser cython. Je pense qu'il devrait être facile d'ajuster un exemple pour ce cas, surtout si vous n'avez pas besoin de beaucoup de flexibilité pour différents types et formes.
la source
J'en avais besoin pour mon travail, alors je me suis appris l'interface C de Python et de Numpy et j'ai écrit la mienne. http://pastebin.com/GtcXuLyd Ce n'est que pour les tableaux 1-D, mais fonctionne pour la plupart des types de données (int, float ou strings) et les tests ont montré qu'il est à nouveau environ 20 fois plus rapide que l'approche attendue en Python pur- engourdi.
la source
Ce problème peut être résolu efficacement en numpy pur en traitant le tableau en morceaux:
Le tableau est traité par bloc de taille
step
. Lestep
plus est l'étape, la plus rapide est le traitement de-gamme mis à zéro ( dans le pire des cas). Plus il est petit, plus le traitement du tableau avec une valeur non nulle au début est rapide. L'astuce consiste à commencer par un petitstep
et à l'augmenter de façon exponentielle. De plus, il n'est pas nécessaire de l'augmenter au-dessus d'un certain seuil en raison des avantages limités.J'ai comparé la solution avec la solution pure ndarary.nonzero et numba contre 10 millions de tableaux de flotteurs.
Et les résultats sur ma machine:
Pure
ndarray.nonzero
est définitivement plus lâche. La solution numba est environ 5 fois plus rapide dans le meilleur des cas. C'est environ 3 fois plus rapide dans le pire des cas.la source
Si vous recherchez le premier élément non nul, vous pouvez utiliser un hack suivant:
C'est une solution "numpy-pure" très rapide mais elle échoue dans certains cas décrits ci-dessous.
La solution tire parti du fait que pratiquement toutes les représentations de zéro pour les types numériques sont constituées d'
0
octets. Cela s'applique également à Numpybool
. Dans les versions récentes de numpy, laargmax()
fonction utilise la logique de court-circuit lors du traitement dubool
type. La taille debool
est de 1 octet.Il faut donc:
bool
. Aucune copie n'est crééeargmax()
pour trouver le premier octet différent de zéro en utilisant la logique de court-circuit//
) de l'offset par une taille d'un seul élément exprimée en octets (x.itemsize
)x[idx]
est réellement non nul pour identifier le cas où aucun non nul n'est présentJ'ai fait une référence par rapport à la solution numba et je l'ai construite
np.nonzero
.Le résultat sur ma machine est:
La solution est 33% plus rapide que numba et elle est "numpy-pure".
Les désavantages:
object
float
ou desdouble
calculsla source
x
avant d'appelernonzero()
. Il sera probablement plus lent que numba mais il ** ne cherchera pas ** dans tout le tableau tout en recherchant la première entrée zéro, il peut donc être assez rapide pour vos besoins.En tant qu'utilisateur de longue date de matlab, je cherche depuis un certain temps une solution efficace à ce problème. Enfin, motivé par des discussions et des propositions dans ce fil, j'ai essayé de trouver une solution qui implémente une API similaire à ce qui a été suggéré ici , ne supportant pour le moment que les tableaux 1D.
Vous l'utiliseriez comme ça
Les opérateurs de condition pris en charge sont: cmp_equal, cmp_not_equal, cmp_larger, cmp_smaller, cmp_larger_eq, cmp_smaller_eq. Pour plus d'efficacité, l'extension est écrite en c.
Vous trouvez la source, les benchmarks et d'autres détails ici:
https://pypi.python.org/pypi?name=py_find_1st&:action=display
pour l'utilisation dans notre équipe (anaconda sur linux et macos) j'ai fait un installeur anaconda qui simplifie l'installation, vous pouvez l'utiliser comme décrit ici
https://anaconda.org/roebel/py_find_1st
la source
Sachez simplement que si vous effectuez une séquence de recherches, le gain de performances en faisant quelque chose d'intelligent comme la conversion en chaîne peut être perdu dans la boucle externe si la dimension de recherche n'est pas assez grande. Voyez comment les performances de l'itération de find1 qui utilise l'astuce de conversion de chaîne proposée ci-dessus et find2 qui utilise argmax le long de l'axe interne (plus un ajustement pour garantir qu'une non-correspondance renvoie -1)
les sorties
Cela dit, une recherche écrite en C serait au moins un peu plus rapide que l'une ou l'autre de ces approches
la source
que dis-tu de ça
la source
where(array==item)[0][0]
de la question ...Vous pouvez convertir votre tableau en un
list
et utiliser saindex()
méthode:Pour autant que je sache, il s'agit d'une méthode compilée en C.
la source
timeit()
sur un tableau de 10000 entiers - la conversion en liste était environ 100 fois plus lente! J'avais oublié que la structure de données sous-jacente pour un tableau numpy est très différente d'une liste ..