wake-up-neo.com

Gibt es eine NumPy-Funktion, um den ersten Index von etwas in einem Array zurückzugeben?

Ich weiß, dass es eine Methode für eine Python -Liste gibt, um den ersten Index von etwas zurückzugeben:

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

Gibt es so etwas für NumPy-Arrays?

408
Nope

Ja, hier ist die Antwort mit einem NumPy-Array array und einem Wert item, nach dem gesucht werden soll:

itemindex = numpy.where(array==item)

Das Ergebnis ist ein Tupel mit zuerst allen Zeilenindizes, dann allen Spaltenindizes.

Wenn zum Beispiel ein Array zweidimensional ist und Ihr Objekt an zwei Stellen enthalten ist, dann

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

wäre gleich zu Ihrem Artikel und so würde

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

numpy.where

476
Alex

Wenn Sie den Index des ersten Auftretens von nur einen Wert benötigen, können Sie nonzero (oder where, was in diesem Fall dasselbe ist) verwenden:

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

Wenn Sie den ersten Index für jeden von viele Werte benötigen, können Sie natürlich das Gleiche wie oben wiederholt tun, aber es gibt einen Trick, der möglicherweise schneller ist. Das Folgende findet die Indizes des ersten Elements jeder Untersequenz :

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

Beachten Sie, dass es den Anfang beider Teilfolgen von 3s und beider Teilfolgen von 8s findet:

[1, 1, 1, 2, 2, , 8, =, 8, 8]

Es ist also etwas anders, als das erste Vorkommen jedes Werts zu finden. In Ihrem Programm können Sie möglicherweise mit einer sortierten Version von t arbeiten, um das zu erhalten, was Sie möchten:

>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
63
Vebjorn Ljosa

Sie können ein NumPy-Array auch in eine Liste in der Luft konvertieren und deren Index abrufen. Zum Beispiel,

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

Es wird 1 ausgegeben.

41
Hima

Nur um eine sehr performante und handliche numba Alternative hinzuzufügen, die auf np.ndenumerate basiert, um den ersten Index zu finden:

_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.
_

Dies ist ziemlich schnell und behandelt natürlich mehrdimensionale Arrays :

_>>> 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,)
_

Dies kann viel schneller sein (weil es die Operation kurzschließt) als jeder Ansatz, der _np.where_ oder _np.nonzero_ verwendet.


Allerdings könnte np.argwhere auch mit mehrdimensionalen Arrays elegant umgehen (Sie müssten es manuell in ein Tupel umwandeln und es ist nicht kurzgeschlossen), aber es würde fehlschlagen, wenn keine Übereinstimmung gefunden wird:

_>>> Tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> Tuple(np.argwhere(arr2 == 2)[0])
(5,)
_
14
MSeifert

Wenn Sie dies als Index für etwas anderes verwenden möchten, können Sie Boolesche Indizes verwenden, wenn die Arrays rundgesendet werden können. Sie brauchen keine expliziten Indizes. Der absolut einfachste Weg, dies zu tun, besteht darin, einfach basierend auf einem Wahrheitswert zu indexieren.

other_array[first_array == item]

Jede boolesche Operation funktioniert:

a = numpy.arange(100)
other_array[first_array > 50]

Die Methode ungleich Null akzeptiert auch Boolesche Werte:

index = numpy.nonzero(first_array == item)[0][0]

Die beiden Nullen sind für das Tupel von Indizes (vorausgesetzt, first_array ist 1D) und dann das erste Element im Array von Indizes.

14
Matt

l.index(x) gibt das kleinste i zurück, so dass i das ist Index des ersten Vorkommens von x in der Liste.

Man kann davon ausgehen, dass die Funktion index() in Python so implementiert ist, dass sie nach dem Finden der ersten Übereinstimmung stoppt und dies zu einer optimalen Durchschnittsleistung führt.

Verwenden Sie einen Iterator ( ndenumerate ), um ein Element zu finden, das nach der ersten Übereinstimmung in einem NumPy-Array stoppt.

In [67]: l=range(100)

In [68]: l.index(2)
Out[68]: 2

NumPy-Array:

In [69]: a = np.arange(100)

In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
Out[70]: (2L,)

Beachten Sie, dass beide Methoden index() und next einen Fehler zurückgeben, wenn das Element nicht gefunden wird. Mit next kann ein zweites Argument verwendet werden, um einen speziellen Wert zurückzugeben, falls das Element nicht gefunden wird, z.

In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)

Es gibt andere Funktionen in NumPy (argmax, where und nonzero), die verwendet werden können, um ein Element in einem Array zu finden, aber alle haben den Nachteil, dass sie das gesamte Array durchlaufen Suche nach allen Vorkommen, daher nicht optimiert, um das erste Element zu finden. Beachten Sie auch, dass where und nonzero Arrays zurückgeben, sodass Sie das erste Element auswählen müssen, um den Index zu erhalten.

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

Zeitvergleich

Wenn Sie nur überprüfen, ob die Lösung für große Arrays mithilfe eines Iterators schneller ist , wenn sich das gesuchte Element am Anfang des Arrays befindet (mit %timeit in) die IPython Shell):

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

Dies ist ein offenes NumPy GitHub-Problem .

Siehe auch: Numpy: finde den ersten Index des Wertes schnell

9
user2314737

Um nach beliebigen Kriterien zu indizieren, können Sie so etwas wie folgendes tun:

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

Und hier ist eine schnelle Funktion, um das zu tun, was list.index () tut, außer dass keine Ausnahme ausgelöst wird, wenn sie nicht gefunden wird. Achtung - dies ist bei großen Arrays wahrscheinlich sehr langsam. Sie können dies wahrscheinlich auf Arrays patchen, wenn Sie es lieber als Methode verwenden möchten.

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
Autoplectic

Für 1D-Arrays würde ich np.flatnonzero(array == value)[0] empfehlen, was sowohl np.nonzero(array == value)[0][0] als auch np.where(array == value)[0][0] entspricht, aber die Hässlichkeit vermeidet, ein Tuple mit 1 Element zu entpacken.

5
1''

Für eindimensionale sortierte Arrays wäre es viel einfacher und effizienter, O(log(n)) zu verwenden - numpy.searchsorted Gibt eine NumPy-Ganzzahl (Position) zurück. Zum Beispiel,

arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)

Stellen Sie einfach sicher, dass das Array bereits sortiert ist

Überprüfen Sie auch, ob der zurückgegebene Index i tatsächlich das gesuchte Element enthält, da das Hauptziel von searchsorted darin besteht, Indizes zu finden, in die Elemente eingefügt werden sollten, um die Reihenfolge aufrechtzuerhalten.

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

In NumPy gibt es viele Operationen, die möglicherweise zusammengestellt werden könnten, um dies zu erreichen. Dies gibt Indizes von Elementen zurück, die gleich item sind:

numpy.nonzero(array - item)

Sie könnten dann die ersten Elemente der Listen nehmen, um ein einzelnes Element zu erhalten.

4
Ned Batchelder

Eine Alternative zum Auswählen des ersten Elements aus np.where () besteht darin, einen Generatorausdruck zusammen mit enumerate zu verwenden, z.

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

Für ein zweidimensionales Array würde man tun:

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

Der Vorteil dieses Ansatzes besteht darin, dass die Elemente des Arrays nicht mehr überprüft werden, nachdem die erste Übereinstimmung gefunden wurde, wohingegen np.where alle Elemente auf eine Übereinstimmung überprüft. Ein Generatorausdruck ist schneller, wenn die Übereinstimmung zu Beginn des Arrays vorliegt.

3
Noyer282

Das numpy_indexed -Paket (Haftungsausschluss, ich bin sein Autor) enthält ein vektorisiertes Äquivalent von list.index für numpy.ndarray; das ist:

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]

Diese Lösung hat eine vektorisierte Leistung, verallgemeinert auf ndarrays und bietet verschiedene Möglichkeiten, mit fehlenden Werten umzugehen.

1