Si vous recherchez la première ligne dans laquelle un élément existe dans la première colonne, cela fonctionne (bien que cela rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
générera
29
Que se passe-t-il si vous souhaitez que la recherche cesse après avoir trouvé la première valeur? Je ne pense pas que () soit comparable à find ()
np.argwhereserait un peu plus utile ici:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Eric
3
Il convient de noter que cette réponse suppose que le tableau est 2D. wherefonctionne sur n'importe quel tableau, et retournera un tuple de longueur 3 lorsqu'il est utilisé sur un tableau 3D, etc.
P. Camilleri
70
Si vous avez besoin de l'index de la première occurrence d' une seule valeur , vous pouvez utiliser nonzero(ou where, ce qui revient au même dans ce cas):
>>> t = array([1,1,1,2,2,3,8,3,8,8])>>> nonzero(t ==8)(array([6,8,9]),)>>> nonzero(t ==8)[0][0]6
Si vous avez besoin du premier index de chacune des nombreuses valeurs , vous pouvez évidemment faire la même chose que ci-dessus à plusieurs reprises, mais il existe une astuce qui peut être plus rapide. Ce qui suit trouve les indices du premier élément de chaque sous- séquence :
Notez qu'il trouve le début de la sous-séquence de 3 et des deux sous-séquences de 8:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
C'est donc légèrement différent de trouver la première occurrence de chaque valeur. Dans votre programme, vous pourrez peut-être travailler avec une version triée de tpour obtenir ce que vous voulez:
>>> st = sorted(t)>>> nonzero(r_[1, diff(st)[:-1]])(array([0,3,5,7]),)
@Geoff, r_concatène; ou, plus précisément, il traduit les objets slice en concaténation le long de chaque axe. J'aurais pu utiliser à la hstackplace; cela peut avoir été moins déroutant. Consultez la documentation pour plus d'informations sur r_. Il y a aussi un c_.
Vebjorn Ljosa
+1, gentil! (vs NP.where) votre solution est beaucoup plus simple (et probablement plus rapide) dans le cas où ce n'est que la première occurrence d'une valeur donnée dans un tableau 1D dont nous avons besoin
doug
3
Ce dernier cas (trouver le premier indice de toutes les valeurs) est donné parvals, locs = np.unique(t, return_index=True)
askewchan
@askewchan votre version est fonctionnellement équivalente, mais beaucoup, beaucoup, beaucoup plus lente
Jivan
50
Vous pouvez également convertir un tableau NumPy en liste dans l'air et obtenir son index. Par exemple,
l =[1,2,3,4,5]# Python list
a = numpy.array(l)# NumPy array
i = a.tolist().index(2)# i will return index of 2print i
Il se peut que la bibliothèque ait changé depuis sa première écriture. Mais ce fut la première solution qui a fonctionné pour moi.
amracel
1
J'en ai fait bon usage pour trouver plusieurs valeurs dans une liste en utilisant une compréhension de liste:[find_list.index(index_list[i]) for i in range(len(index_list))]
Matt Wenham
1
@MattWenham Si c'est assez grand, vous pouvez convertir votre find_listen un tableau NumPy object(ou quelque chose de plus spécifique qui soit approprié) et faites-le find_arr[index_list].
Narfanar
Totalement hors sujet, mais c'est la première fois que je vois l'expression "dans l'air" - ce que j'ai vu le plus, à sa place, est probablement "à la volée".
flow2k
18
Juste pour ajouter un très performant et pratique numbaalternative basée sur np.ndenumeratepour trouver le premier index:
from numba import njit
import numpy as np
@njitdef index(array, item):for idx, val in np.ndenumerate(array):if val == item:return idx
# If no item was found return None, other return types might be a problem due to# numbas type inference.
C'est assez rapide et traite naturellement des tableaux multidimensionnels :
Cela peut être beaucoup plus rapide (car il court-circuite l'opération) que toute approche utilisant np.whereou np.nonzero.
Cependant, cela np.argwherepourrait également fonctionner avec élégance avec les tableaux multidimensionnels (vous auriez besoin de le convertir manuellement en un tuple et il n'est pas court-circuité), mais il échouerait si aucune correspondance n'était trouvée:
@njitest un raccourci de jit(nopython=True)la fonction sera entièrement compilée à la volée au moment de la première exécution afin que les appels de l'interpréteur Python soient complètement supprimés.
bartolo-otrit
14
Si vous allez utiliser ceci comme index dans quelque chose d'autre, vous pouvez utiliser des index booléens si les tableaux sont diffusables; vous n'avez pas besoin d'indices explicites. La façon la plus simple de procéder consiste à simplement indexer en fonction d'une valeur de vérité.
other_array[first_array == item]
Toute opération booléenne fonctionne:
a = numpy.arange(100)
other_array[first_array >50]
La méthode non nulle prend aussi des booléens:
index = numpy.nonzero(first_array == item)[0][0]
Les deux zéros correspondent au tuple d'indices (en supposant que first_array est 1D), puis au premier élément du tableau d'indices.
l.index(x)renvoie le plus petit i tel que i soit l'indice de la première occurrence de x dans la liste.
On peut supposer en toute sécurité que la index()fonction en Python est implémentée de manière à ce qu'elle s'arrête après avoir trouvé la première correspondance, et cela se traduit par une performance moyenne optimale.
Pour trouver un élément s'arrêtant après la première correspondance dans un tableau NumPy, utilisez un itérateur ( ndenumerate ).
In[67]: l=range(100)In[68]: l.index(2)Out[68]:2
Tableau NumPy:
In[69]: a = np.arange(100)In[70]: next((idx for idx, val in np.ndenumerate(a)if val==2))Out[70]:(2L,)
Notez que les deux méthodes index()et nextrenvoient une erreur si l'élément est introuvable. Avec next, on peut utiliser un deuxième argument pour retourner une valeur spéciale au cas où l'élément ne serait pas trouvé, par exemple
In[77]: next((idx for idx, val in np.ndenumerate(a)if val==400),None)
Il existe d' autres fonctions dans NumPy ( argmax, whereet nonzero) qui peut être utilisé pour trouver un élément dans un tableau, mais ils ont tous l'inconvénient de passer par le tableau entier à la recherche de toutes les occurrences, donc pas optimisé pour trouver le premier élément. Notez également cela whereet nonzerorenvoyez des tableaux, vous devez donc sélectionner le premier élément pour obtenir l'index.
Vérifier simplement que pour les grands tableaux, la solution utilisant un itérateur est plus rapide lorsque l'élément recherché est au début du tableau (en utilisant %timeitdans le shell IPython):
In[285]: a = np.arange(100000)In[286]:%timeit next((idx for idx, val in np.ndenumerate(a)if val==0))100000 loops, best of 3:17.6µs per loop
In[287]:%timeit np.argmax(a==0)1000 loops, best of 3:254µs per loop
In[288]:%timeit np.where(a==0)[0][0]1000 loops, best of 3:314µs per loop
Je pense que vous devriez également inclure un calendrier pour le pire des cas (dernier élément) afin que les lecteurs sachent ce qui leur arrive dans le pire des cas lorsqu'ils utilisent votre approche.
MSeifert
@MSeifert Je n'arrive pas à obtenir un délai raisonnable pour la solution d'itérateur du pire des cas - je vais supprimer cette réponse jusqu'à ce que je découvre ce qui ne va pas
user2314737
1
ne %timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))fonctionne pas ? Si vous vous demandez pourquoi il est 1000 fois plus lent - c'est parce que les boucles python sur les tableaux numpy sont notoirement lentes.
MSeifert
@MSeifert non, je ne le savais pas, mais je suis aussi perplexe par le fait que argmaxet wheresont beaucoup plus rapides dans ce cas (élément recherché à la fin du tableau)
user2314737
Ils doivent être aussi rapides que si l'élément est au début. Ils traitent toujours l'ensemble du tableau, donc ils prennent toujours le même temps (du moins ils devraient).
MSeifert
9
Pour les tableaux triés unidimensionnels , il serait beaucoup plus simple et efficace O (log (n)) d'utiliser numpy.searchsorted qui renvoie un entier NumPy (position). Par exemple,
arr = np.array([1,1,1,2,3,3,4])
i = np.searchsorted(arr,3)
Assurez-vous simplement que le tableau est déjà trié
Vérifiez également si l'index retourné i contient réellement l'élément recherché, car l'objectif principal de searchsorted est de trouver des indices dans lesquels les éléments doivent être insérés pour maintenir l'ordre.
if arr[i]==3:print("present")else:print("not present")
searchsorted n'est pas nlog (n) car il ne trie pas le tableau avant la recherche, il suppose que le tableau d'arguments est déjà trié. consultez la documentation de numpy.searchsorted (lien ci-dessus)
Alok Nayak
6
Pour indexer sur n'importe quel critère, vous pouvez donc quelque chose comme ceci:
In[1]:from numpy import*In[2]: x = arange(125).reshape((5,5,5))In[3]: y = indices(x.shape)In[4]: locs = y[:,x >=120]# put whatever you want in place of x >= 120In[5]: pts = hsplit(locs, len(locs[0]))In[6]:for pt in pts:.....:print(', '.join(str(p[0])for p in pt))4,4,04,4,14,4,24,4,34,4,4
Et voici une fonction rapide pour faire ce que fait list.index (), sauf qu'il ne déclenche pas d'exception s'il n'est pas trouvé. Attention - cela est probablement très lent sur les grands tableaux. Vous pouvez probablement corriger cela sur des tableaux si vous préférez l'utiliser comme méthode.
def ndindex(ndarray, item):if len(ndarray.shape)==1:try:return[ndarray.tolist().index(item)]except:passelse:for i, subarray in enumerate(ndarray):try:return[i]+ ndindex(subarray, item)except:passIn[1]: ndindex(x,103)Out[1]:[4,0,3]
Pour les tableaux 1D, je recommanderais np.flatnonzero(array == value)[0], ce qui équivaut aux deux np.nonzero(array == value)[0][0]et np.where(array == value)[0][0]évite la laideur de déballer un tuple à 1 élément.
Une alternative à la sélection du premier élément dans np.where () consiste à utiliser une expression de générateur avec énumération, telle que:
>>>import numpy as np
>>> x = np.arange(100)# x = array([0, 1, 2, 3, ... 99])>>> next(i for i, x_i in enumerate(x)if x_i ==2)2
Pour un tableau à deux dimensions, on ferait:
>>> x = np.arange(100).reshape(10,10)# x = array([[0, 1, 2,... 9], [10,..19],])>>> next((i,j)for i, x_i in enumerate(x)...for j, x_ij in enumerate(x_i)if x_ij ==2)(0,2)
L'avantage de cette approche est qu'elle arrête de vérifier les éléments du tableau une fois la première correspondance trouvée, tandis que np.where vérifie la correspondance de tous les éléments. Une expression de générateur serait plus rapide s'il y a correspondance au début du tableau.
Dans le cas où il pourrait ne pas y avoir de correspondance dans le tableau, cette méthode vous permet également de spécifier facilement une valeur de secours. Si le premier exemple revenait Nonecomme solution de rechange, il le deviendrait next((i for i, x_i in enumerate(x) if x_i == 2), None).
Erlend Magnus Viggen
4
Il existe de nombreuses opérations dans NumPy qui pourraient peut-être être regroupées pour y parvenir. Cela renverra des indices d'éléments égaux à l'élément:
numpy.nonzero(array - item)
Vous pouvez ensuite prendre les premiers éléments des listes pour obtenir un seul élément.
Réponses:
Oui, voici la réponse donnée un tableau NumPy,
array
, et une valeuritem
, pour rechercher:Le résultat est un tuple avec d'abord tous les indices de ligne, puis tous les indices de colonne.
Par exemple, si un tableau a deux dimensions et qu'il contenait votre article à deux endroits,
serait égal à votre article et il en serait de même
numpy.where
la source
rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
np.argwhere
serait un peu plus utile ici:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
fonctionne sur n'importe quel tableau, et retournera un tuple de longueur 3 lorsqu'il est utilisé sur un tableau 3D, etc.Si vous avez besoin de l'index de la première occurrence d' une seule valeur , vous pouvez utiliser
nonzero
(ouwhere
, ce qui revient au même dans ce cas):Si vous avez besoin du premier index de chacune des nombreuses valeurs , vous pouvez évidemment faire la même chose que ci-dessus à plusieurs reprises, mais il existe une astuce qui peut être plus rapide. Ce qui suit trouve les indices du premier élément de chaque sous- séquence :
Notez qu'il trouve le début de la sous-séquence de 3 et des deux sous-séquences de 8:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
C'est donc légèrement différent de trouver la première occurrence de chaque valeur. Dans votre programme, vous pourrez peut-être travailler avec une version triée de
t
pour obtenir ce que vous voulez:la source
r_
c'est?r_
concatène; ou, plus précisément, il traduit les objets slice en concaténation le long de chaque axe. J'aurais pu utiliser à lahstack
place; cela peut avoir été moins déroutant. Consultez la documentation pour plus d'informations surr_
. Il y a aussi unc_
.vals, locs = np.unique(t, return_index=True)
Vous pouvez également convertir un tableau NumPy en liste dans l'air et obtenir son index. Par exemple,
Il imprimera 1.
la source
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
en un tableau NumPyobject
(ou quelque chose de plus spécifique qui soit approprié) et faites-lefind_arr[index_list]
.Juste pour ajouter un très performant et pratique numbaalternative basée sur
np.ndenumerate
pour trouver le premier index:C'est assez rapide et traite naturellement des tableaux multidimensionnels :
Cela peut être beaucoup plus rapide (car il court-circuite l'opération) que toute approche utilisant
np.where
ounp.nonzero
.Cependant, cela
np.argwhere
pourrait également fonctionner avec élégance avec les tableaux multidimensionnels (vous auriez besoin de le convertir manuellement en un tuple et il n'est pas court-circuité), mais il échouerait si aucune correspondance n'était trouvée:la source
@njit
est un raccourci dejit(nopython=True)
la fonction sera entièrement compilée à la volée au moment de la première exécution afin que les appels de l'interpréteur Python soient complètement supprimés.Si vous allez utiliser ceci comme index dans quelque chose d'autre, vous pouvez utiliser des index booléens si les tableaux sont diffusables; vous n'avez pas besoin d'indices explicites. La façon la plus simple de procéder consiste à simplement indexer en fonction d'une valeur de vérité.
Toute opération booléenne fonctionne:
La méthode non nulle prend aussi des booléens:
Les deux zéros correspondent au tuple d'indices (en supposant que first_array est 1D), puis au premier élément du tableau d'indices.
la source
l.index(x)
renvoie le plus petit i tel que i soit l'indice de la première occurrence de x dans la liste.On peut supposer en toute sécurité que la
index()
fonction en Python est implémentée de manière à ce qu'elle s'arrête après avoir trouvé la première correspondance, et cela se traduit par une performance moyenne optimale.Pour trouver un élément s'arrêtant après la première correspondance dans un tableau NumPy, utilisez un itérateur ( ndenumerate ).
Tableau NumPy:
Notez que les deux méthodes
index()
etnext
renvoient une erreur si l'élément est introuvable. Avecnext
, on peut utiliser un deuxième argument pour retourner une valeur spéciale au cas où l'élément ne serait pas trouvé, par exempleIl existe d' autres fonctions dans NumPy (
argmax
,where
etnonzero
) qui peut être utilisé pour trouver un élément dans un tableau, mais ils ont tous l'inconvénient de passer par le tableau entier à la recherche de toutes les occurrences, donc pas optimisé pour trouver le premier élément. Notez également celawhere
etnonzero
renvoyez des tableaux, vous devez donc sélectionner le premier élément pour obtenir l'index.Comparaison de temps
Vérifier simplement que pour les grands tableaux, la solution utilisant un itérateur est plus rapide lorsque l'élément recherché est au début du tableau (en utilisant
%timeit
dans le shell IPython):Il s'agit d'un problème ouvert avec NumPy GitHub .
Voir aussi: Numpy: trouver rapidement le premier indice de valeur
la source
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
fonctionne pas ? Si vous vous demandez pourquoi il est 1000 fois plus lent - c'est parce que les boucles python sur les tableaux numpy sont notoirement lentes.argmax
etwhere
sont beaucoup plus rapides dans ce cas (élément recherché à la fin du tableau)Pour les tableaux triés unidimensionnels , il serait beaucoup plus simple et efficace O (log (n)) d'utiliser numpy.searchsorted qui renvoie un entier NumPy (position). Par exemple,
Assurez-vous simplement que le tableau est déjà trié
Vérifiez également si l'index retourné i contient réellement l'élément recherché, car l'objectif principal de searchsorted est de trouver des indices dans lesquels les éléments doivent être insérés pour maintenir l'ordre.
la source
Pour indexer sur n'importe quel critère, vous pouvez donc quelque chose comme ceci:
Et voici une fonction rapide pour faire ce que fait list.index (), sauf qu'il ne déclenche pas d'exception s'il n'est pas trouvé. Attention - cela est probablement très lent sur les grands tableaux. Vous pouvez probablement corriger cela sur des tableaux si vous préférez l'utiliser comme méthode.
la source
Pour les tableaux 1D, je recommanderais
np.flatnonzero(array == value)[0]
, ce qui équivaut aux deuxnp.nonzero(array == value)[0][0]
etnp.where(array == value)[0][0]
évite la laideur de déballer un tuple à 1 élément.la source
Une alternative à la sélection du premier élément dans np.where () consiste à utiliser une expression de générateur avec énumération, telle que:
Pour un tableau à deux dimensions, on ferait:
L'avantage de cette approche est qu'elle arrête de vérifier les éléments du tableau une fois la première correspondance trouvée, tandis que np.where vérifie la correspondance de tous les éléments. Une expression de générateur serait plus rapide s'il y a correspondance au début du tableau.
la source
None
comme solution de rechange, il le deviendraitnext((i for i, x_i in enumerate(x) if x_i == 2), None)
.Il existe de nombreuses opérations dans NumPy qui pourraient peut-être être regroupées pour y parvenir. Cela renverra des indices d'éléments égaux à l'élément:
Vous pouvez ensuite prendre les premiers éléments des listes pour obtenir un seul élément.
la source
Le paquet numpy_indexed (avertissement, je suis son auteur) contient un équivalent vectorisé de list.index pour numpy.ndarray; C'est:
Cette solution a des performances vectorisées, se généralise en ndarrays et a différentes manières de traiter les valeurs manquantes.
la source
Remarque: c'est pour la version python 2.7
Vous pouvez utiliser une fonction lambda pour résoudre le problème, et elle fonctionne à la fois sur le tableau et la liste NumPy.
Et vous pouvez utiliser
pour obtenir le premier index des éléments filtrés.
Pour python 3.6, utilisez
au lieu de
la source
<filter object at 0x0000027535294D30>
sur Python 3 (testé sur Python 3.6.3). Peut-être une mise à jour pour Python 3?