Existe-t-il une fonction NumPy pour renvoyer le premier index de quelque chose dans un tableau?

StackOverflow https://stackoverflow.com/questions/432112

  •  08-07-2019
  •  | 
  •  

Question

Je sais qu'il existe une méthode permettant à une liste Python de renvoyer le premier index de quelque chose:

>>> l = [1, 2, 3]
>>> l.index(2)
1

Existe-t-il quelque chose comme ça pour les tableaux NumPy?

Était-ce utile?

La solution

Oui, voici la réponse: un tableau NumPy, tableau et une valeur, élément , dans lesquels rechercher:

itemindex = numpy.where(array==item)

Le résultat est un tuple avec d'abord tous les index de lignes, puis tous les index de colonnes.

Par exemple, si un tableau a deux dimensions et qu'il contient votre élément à deux emplacements, alors

array[itemindex[0][0]][itemindex[1][0]]

serait égal à votre élément et il en serait de même

array[itemindex[0][1]][itemindex[1][1]]

numpy.where

Autres conseils

Si vous avez besoin de l'index de la première occurrence de une seule valeur , vous pouvez utiliser non nul (ou , ce qui revient à 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 chacune des nombreuses valeurs , vous pouvez évidemment procéder de la même manière que ci-dessus, mais il existe une astuce qui peut être plus rapide. Vous trouverez ci-dessous les indices du premier élément de chaque sous-séquence :

>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)

Notez qu'il trouve le début des deux sous-séquences de 3 et de 8s:

[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]

Il est donc légèrement différent de rechercher la première occurrence de chaque valeur. Dans votre programme, vous pourrez peut-être utiliser 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 NumPy en liste 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 imprimera 1.

Si vous voulez utiliser cela comme un index vers quelque chose d'autre, vous pouvez utiliser des index booléens si les tableaux sont diffusables; vous n'avez pas besoin d'indices explicites. Pour ce faire, la méthode la plus simple consiste à indexer simplement sur 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 également 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'index 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 la recherche de la première correspondance, ce qui entraîne des performances moyennes optimales.

Pour rechercher un élément s'arrêtant après la première correspondance d'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 suivant renvoient une erreur si l'élément n'est pas trouvé. Avec next , vous pouvez utiliser un deuxième argument pour renvoyer 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 , et non nul ) qui peuvent être utilisées pour rechercher un élément dans un tableau, mais ils ont tous l’inconvénient de parcourir l’ensemble du tableau à la recherche de toutes occurrences, de sorte qu’elles ne sont pas optimisées pour la recherche du premier élément. Notez également que where et non nul renvoient des tableaux, 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 du temps

Il suffit de vérifier que, pour les grands tableaux, la solution utilisant un itérateur est plus rapide lorsque l'élément recherché se trouve 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

Il s'agit d'un numéro de NumPy GitHub ouvert.

Voir aussi: Numpy: recherche rapidement le premier index de valeur

Pour indexer sur n'importe quel critère, vous pouvez utiliser 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 >= 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 permettant de faire ce que list.index () fait, sauf que cela ne déclenche pas d'exception s'il n'est pas trouvé. Attention - ceci est probablement très lent sur les grands tableaux. Si vous préférez l’utiliser comme méthode, vous pouvez probablement appliquer ce correctif à des tableaux à l'aide de singe.

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]

Pour les tableaux 1D, je recommanderais np.flatnonzero (tableau == valeur) [0] , ce qui équivaut à la fois np.nonzero (tableau == valeur) [0 ] [0] et np.where (tableau == valeur) [0] [0] , mais évite la laideur de déconditionner un tuple à 1 élément.

NumPy propose de nombreuses opérations qui pourraient être mises en place pour atteindre cet objectif. Cela retournera des indices d'éléments égaux à item:

numpy.nonzero(array - item)

Vous pouvez ensuite utiliser les premiers éléments des listes pour obtenir un seul élément.

Pour les tableaux triés unidimensionnels, il serait beaucoup plus simple et efficace d’utiliser 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 renvoyé i contient réellement l'élément recherché, l'objectif principal de searchsorted étant de rechercher des index où des éléments doivent être insérés pour maintenir l'ordre.

if arr[i] == 3:
    print("present")
else:
    print("not present")

Une alternative à la sélection du premier élément de np.where () consiste à utiliser une expression génératrice avec enumerate, 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 lorsque la première correspondance est trouvée, alors que np.where vérifie la correspondance de tous les éléments. Une expression génératrice serait plus rapide s'il y avait une correspondance au début du tableau.

Le package numpy_indexed contient un équivalent vectorisé de list.index. pour 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é les performances, généralisée à ndarrays et dispose de différentes façons de traiter les valeurs manquantes.

Remarque: il s'agit de la version Python 2.7

Vous pouvez utiliser une fonction lambda pour traiter le problème et cela fonctionne à la fois sur les tableaux et les listes NumPy.

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, utilisez

list(result)

au lieu de

result
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top