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?

323
demandé sur Peter Mortensen 2009-01-11 04:21:39

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]]

numpy.où

402
répondu Alex 2018-09-12 20:29:41

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]),)
59
répondu Vebjorn Ljosa 2009-06-25 15:01:00

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.

32
répondu Hima 2018-06-26 20:15:38

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.

14
répondu Matt 2009-01-11 03:52:49

juste pour ajouter un très performant et pratique 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,)
8
répondu MSeifert 2018-01-18 09:38:08

À 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]
6
répondu Autoplectic 2018-06-26 20:14:10

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

5
répondu user2314737 2018-06-26 20:21:23

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.

4
répondu 1'' 2017-02-05 07:41:00

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.

4
répondu Ned Batchelder 2018-06-26 20:12:17

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.

3
répondu Alok Nayak 2018-08-07 16:46:19

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.

2
répondu Noyer282 2016-11-04 21:21:54

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.

1
répondu Eelco Hoogendoorn 2017-07-12 14:51:55

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
-1
répondu Statham 2018-06-27 01:10:19