Y a-t-il une fonction NumPy pour retourner le premier index de quelque chose dans un tableau?
je sais qu'il existe une méthode pour qu'une liste Python renvoie le premier index de quelque chose:
>>> l = list([1, 2, 3])
>>> l.index(2)
1
y a-t-il quelque chose comme ça pour les tableaux de NumPy?
13 réponses
Oui, ici est la réponse donnée d'un tableau NumPy, array
, et une valeur, item
, à la recherche pour:
itemindex = numpy.where(array==item)
Le résultat est un tuple avec d'abord tous les indices de ligne, puis toute la colonne d'indices.
par exemple, si un tableau est de deux dimensions et qu'il contient votre article à deux endroits, alors
array[itemindex[0][0]][itemindex[1][0]]
serait égal à votre article et ainsi serait
array[itemindex[0][1]][itemindex[1][1]]
si vous avez besoin de l'index de la première occurrence de une seule valeur , vous pouvez utiliser nonzero
(ou where
, ce qui revient à la même chose 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 chacun des beaucoup de valeurs , vous pouvez évidemment faire la même chose que ci-dessus à plusieurs reprises, mais il ya une astuce qui peut être plus rapide. Le suivant trouve les indices du premier élément de chaque subsequence :
>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)
remarquez qu'il trouve le début à la fois de la postérité de 3s et des postérieures de 8s:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
donc c'est légèrement différent de trouver le premier occurrence de chaque valeur. Dans votre programme, vous pourriez être en mesure de travailler avec une version triée de t
pour obtenir ce que vous voulez:
>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
vous pouvez également convertir un tableau de NumPy à la 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 2
print i
il affichera 1.
si vous allez utiliser ceci comme un index dans quelque chose d'autre, vous pouvez utiliser des indices booléens si les tableaux sont diffusables; vous n'avez pas besoin d'indices explicites. La manière la plus simple de le faire est de simplement indexer sur la base 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 zéro prend booleans, aussi:
index = numpy.nonzero(first_array == item)[0][0]
les deux zéros sont pour le tuple des indices (en supposant que first_array est 1D) puis le premier élément du tableau des indices.
juste pour ajouter un très performant et pratique numba alternative basée sur np.ndenumerate
pour trouver le premier index:
from numba import njit
import numpy as np
@njit
def 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 avec les tableaux multidimensionnels :
>>> arr1 = np.ones((100, 100, 100))
>>> arr1[2, 2, 2] = 2
>>> index(arr1, 2)
(2, 2, 2)
>>> arr2 = np.ones(20)
>>> arr2[5] = 2
>>> index(arr2, 2)
(5,)
cela peut être beaucoup plus rapide (parce que c'est court-circuiter l'opération) que n'importe quelle approche utilisant np.where
ou np.nonzero
.
cependant np.argwhere
pourrait aussi traiter avec élégance avec des tableaux multidimensionnels (vous auriez besoin de le lancer manuellement à un tuple et il n'est pas court-circuité) mais il échouerait si aucune correspondance n'est trouvée:
>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)
À l'index sur tous les critères, vous pouvez donc quelque chose comme ce qui suit:
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 >= 120
In [5]: pts = hsplit(locs, len(locs[0]))
In [6]: for pt in pts:
.....: print(', '.join(str(p[0]) for p in pt))
4, 4, 0
4, 4, 1
4, 4, 2
4, 4, 3
4, 4, 4
et voici une fonction rapide pour faire quelle liste.index () le fait, sauf que ne soulève pas d'exception si elle n'est pas trouvée. Attention -- ceci est probablement très lent sur les grands tableaux. Vous pouvez probablement monkey patch cette à des tableaux si vous préférez l'utiliser comme une méthode.
def ndindex(ndarray, item):
if len(ndarray.shape) == 1:
try:
return [ndarray.tolist().index(item)]
except:
pass
else:
for i, subarray in enumerate(ndarray):
try:
return [i] + ndindex(subarray, item)
except:
pass
In [1]: ndindex(x, 103)
Out[1]: [4, 0, 3]
l.index(x)
retourne le plus petit i tel que i est l'indice de la première occurrence de x dans la liste.
on peut supposer en toute sécurité que la fonction index()
en Python est implémentée de sorte qu'elle s'arrête après avoir trouvé la première correspondance, ce qui 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 next
renvoie une erreur si l'élément n'est pas trouvé. Avec next
, on peut utiliser un second argument pour retourner une valeur spéciale dans le cas où l'élément n'est pas trouvé, par exemple
In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)
il y a d'autres fonctions dans NumPy ( argmax
, where
, et nonzero
) que peut être utilisé pour trouver un élément dans un tableau, mais ils ont tous l'inconvénient de passer par l'ensemble du tableau à la recherche de tous occurrences, donc pas être optimisé pour trouver le premier élément. Notez également que les tableaux de retour where
et nonzero
, vous devez donc sélectionner le premier élément pour obtenir l'index.
In [71]: np.argmax(a==2)
Out[71]: 2
In [72]: np.where(a==2)
Out[72]: (array([2], dtype=int64),)
In [73]: np.nonzero(a==2)
Out[73]: (array([2], dtype=int64),)
comparaison des Temps de
je vérifie juste que pour les grands tableaux la solution en 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):
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
C'est ouvert NumPy GitHub question .
voir aussi: Numpy: trouver le premier indice de valeur fast
pour les matrices 1D, je recommande np.flatnonzero(array == value)[0]
, ce qui est équivalent à la fois np.nonzero(array == value)[0][0]
et np.where(array == value)[0][0]
mais évite la laideur de déballer un tuple 1-element.
il y a beaucoup d'opérations à NumPy qui pourraient peut-être être rassemblées pour accomplir ceci. Vous obtiendrez des indices d'éléments égaux à item:
numpy.nonzero(array - item)
, Vous pouvez alors prendre les premiers éléments de la liste d'un seul élément.
pour les matrices unidimensionnelles triées , il serait beaucoup plus simple et efficace O(log(n)) d'utiliser numpy.searchsorted qui renvoie un NumPy entier (position). Par exemple,
i = np.searchsorted(np.array([1, 1, 1, 2, 3, 3, 4]), 3)
assurez-vous de trier le tableau avant si elle n'est pas déjà triées.
une solution de rechange au choix du premier élément à partir du np.où() doit utiliser une expression de générateur avec enumerate, tel 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 bidimensionnel 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 cesse de vérifier les éléments du tableau après que la première correspondance est trouvée, alors que np.où vérifie tous les éléments pour une correspondance. Une expression de générateur serait plus rapide s'il y avait match early dans le tableau.
le paquet numpy_indexed (disclaimer, je suis son auteur) contient un équivalent vectorisé de list.indice de numpy.ndarray; c'est-à-dire:
sequence_of_arrays = [[0, 1], [1, 2], [-5, 0]]
arrays_to_query = [[-5, 0], [1, 0]]
import numpy_indexed as npi
idx = npi.indices(sequence_of_arrays, arrays_to_query, missing=-1)
print(idx) # [2, -1]
cette solution a vectorisé la performance, généralise à ndarrays, et a différentes façons de traiter les valeurs manquantes.
Note: Ceci est pour python 2.7 version
vous pouvez utiliser une fonction lambda pour traiter le problème, et il fonctionne à la fois sur le tableau de NumPy et la liste.
your_list = [11, 22, 23, 44, 55]
result = filter(lambda x:your_list[x]>30, range(len(your_list)))
#result: [3, 4]
import numpy as np
your_numpy_array = np.array([11, 22, 23, 44, 55])
result = filter(lambda x:your_numpy_array [x]>30, range(len(your_list)))
#result: [3, 4]
et vous pouvez utiliser
result[0]
pour obtenir le premier index des éléments filtrés.
pour python 3.6, utiliser
list(result)
au lieu de
result