Wenn Sie nach der ersten Zeile suchen, in der ein Element in der ersten Spalte vorhanden ist, funktioniert dies (obwohl es einen Indexfehler rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
auslöst,
27
Was ist, wenn die Suche nach dem ersten Wert beendet werden soll? Ich denke nicht, wo () vergleichbar ist mit find ()
Michael Clerx
2
Ah! Wenn Sie an Leistung interessiert sind, lesen Sie
Michael Clerx
11
np.argwherewäre hier etwas nützlicher:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Eric
3
Es ist erwähnenswert, dass diese Antwort davon ausgeht, dass das Array 2D ist. wherefunktioniert auf jedem Array und gibt ein Tupel der Länge 3 zurück, wenn es auf einem 3D-Array usw. verwendet wird.
P. Camilleri
69
Wenn Sie den Index des ersten Auftretens nur eines Werts benötigen , können Sie Folgendes verwenden nonzero(oder where, was in diesem Fall dasselbe bedeutet):
>>> 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 vielen Werten benötigen , können Sie natürlich wiederholt dasselbe wie oben tun, aber es gibt einen Trick, der möglicherweise schneller ist. Im Folgenden werden die Indizes des ersten Elements jeder Teilsequenz ermittelt :
Beachten Sie, dass der Anfang beider Teilsequenzen von 3s und beider Teilsequenzen von 8s gefunden wird:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Es ist also etwas anders als das erste zu finden Auftreten jedes Werts zu finden. In Ihrem Programm können Sie möglicherweise mit einer sortierten Version von arbeiten t, um das zu erhalten, was Sie möchten:
>>> st = sorted(t)>>> nonzero(r_[1, diff(st)[:-1]])(array([0,3,5,7]),)
@Geoff, r_verkettet; oder genauer gesagt, es übersetzt Slice-Objekte in Verkettung entlang jeder Achse. Ich hätte hstackstattdessen verwenden können; das mag weniger verwirrend gewesen sein. Weitere Informationen finden Sie in der Dokumentationr_ . Es gibt auch eine c_.
Vebjorn Ljosa
+1, schön! (vs NP.where) Ihre Lösung ist viel einfacher (und wahrscheinlich schneller), wenn es nur das erste Auftreten eines bestimmten Werts in einem 1D-Array ist, das wir benötigen
Doug
3
Der letztere Fall (Finden des ersten Index aller Werte) ist gegeben durchvals, locs = np.unique(t, return_index=True)
askewchan
50
Sie können auch ein NumPy-Array in eine Liste in der Luft konvertieren und dessen 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 2print i
Möglicherweise hat sich die Bibliothek seit dem ersten Schreiben geändert. Dies war jedoch die erste Lösung, die für mich funktioniert hat.
Amracel
1
Ich habe dies gut genutzt, um mehrere Werte in einer Liste mithilfe eines Listenverständnisses zu finden:[find_list.index(index_list[i]) for i in range(len(index_list))]
Matt Wenham
1
@MattWenham Wenn es groß genug ist, können Sie es find_listin ein NumPy-Array von object(oder etwas Spezifischerem, das angemessen ist) konvertieren und es einfach tun find_arr[index_list].
Narfanar
Völlig unangebracht, aber dies ist das erste Mal, dass ich den Satz "in der Luft" sehe - was ich an seiner Stelle am meisten gesehen habe, ist wahrscheinlich "on the fly".
flow2k
18
Nur um eine sehr performante und handliche hinzuzufügen numbaAlternative basierend auf np.ndenumerate, um den ersten Index zu finden:
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.
Dies ist ziemlich schnell und befasst sich natürlich mit mehrdimensionalen Arrays :
Dies kann viel schneller sein (weil es die Operation kurzschließt) als jeder Ansatz, der np.whereoder verwendet np.nonzero.
Allerdings np.argwherekönnte auch behandeln anmutig mit mehrdimensionalen Arrays (Sie würden müssen manuell in ein Tupel geworfen es und es ist nicht kurzgeschlossen) , aber es würde scheitern , wenn keine Übereinstimmung gefunden wird:
@njitist eine Abkürzung von jit(nopython=True)dh die Funktion wird zum Zeitpunkt des ersten Durchlaufs im laufenden Betrieb vollständig kompiliert, sodass die Python-Interpreter-Aufrufe vollständig entfernt werden.
Bartolo-Otrit
14
Wenn Sie dies als Index für etwas anderes verwenden möchten, können Sie boolesche Indizes verwenden, wenn die Arrays sendbar sind. Sie benötigen keine expliziten Indizes. Der absolut einfachste Weg, dies zu tun, besteht darin, einfach basierend auf einem Wahrheitswert zu indizieren.
other_array[first_array == item]
Jede boolesche Operation funktioniert:
a = numpy.arange(100)
other_array[first_array >50]
Die Nicht-Null-Methode verwendet auch Boolesche Werte:
index = numpy.nonzero(first_array == item)[0][0]
Die beiden Nullen stehen für das Tupel von Indizes (vorausgesetzt, first_array ist 1D) und dann für das erste Element im Array von Indizes.
l.index(x)Gibt das kleinste i zurück , sodass i der Index des ersten Auftretens von x in der Liste ist.
Man kann davon ausgehen, dass die index()Funktion in Python so implementiert ist, dass sie nach dem Finden der ersten Übereinstimmung stoppt, und dies führt zu einer optimalen Durchschnittsleistung.
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 nexteinen Fehler zurückgeben, wenn das Element nicht gefunden wird. Mit nextkann man ein zweites Argument verwenden, 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 auch andere Funktionen in NumPy ( argmax, where, und nonzero) , die verwendet werden kann , ein Element in einem Array zu finden, aber sie haben alle den Nachteil , daß durch die ganze Reihe gehen auf der Suche nach allen Vorkommen, also nicht zum Auffinden des ersten Elements optimiert. Beachten Sie auch das whereund nonzerogeben Sie Arrays zurück, sodass Sie das erste Element auswählen müssen, um den Index abzurufen.
Wenn Sie nur überprüfen, ob bei großen Arrays die Lösung mithilfe eines Iterators schneller ist, wenn sich das gesuchte Element am Anfang des Arrays befindet (mithilfe %timeitder 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
Ich denke, Sie sollten auch ein Timing für den schlimmsten Fall (letztes Element) angeben, damit die Leser wissen, was mit ihnen im schlimmsten Fall passiert, wenn sie Ihren Ansatz verwenden.
MSeifert
@ MSeifert Ich kann kein vernünftiges Timing für die Iteratorlösung im schlimmsten Fall bekommen - ich werde diese Antwort löschen, bis ich herausfinde, was daran falsch ist
user2314737
1
funktioniert nicht %timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))? Wenn Sie sich fragen, warum es 1000-mal langsamer ist, dann deshalb, weil Python-Loops über numpy Arrays notorisch langsam sind.
MSeifert
@MSeifert nein das wusste ich nicht, aber ich bin auch verwirrt darüber, dass argmaxund wherein diesem Fall viel schneller sind (gesuchtes Element am Ende des Arrays)
user2314737
Sie sollten so schnell sein, als ob das Element am Anfang steht. Sie verarbeiten immer das gesamte Array, sodass sie immer die gleiche Zeit benötigen (zumindest sollten sie dies tun).
MSeifert
9
Für eindimensional sortierte Arrays wäre es viel einfacher und effizienter, O (log (n)) zu verwenden, indem numpy.searchsorted verwendet wird, das eine NumPy-Ganzzahl (Position) zurückgibt. 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 sollen, um die Reihenfolge aufrechtzuerhalten.
if arr[i]==3:print("present")else:print("not present")
searchsorted ist nicht nlog (n), da das Array vor der Suche nicht sortiert wird. Es wird davon ausgegangen, dass das Argumentarray bereits sortiert ist. Schauen Sie sich die Dokumentation von numpy.searchsorted an (Link oben)
Alok Nayak
6
Um nach Kriterien zu indizieren, können Sie so etwas wie das Folgende 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 >= 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
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:passelse:for i, subarray in enumerate(ndarray):try:return[i]+ ndindex(subarray, item)except:passIn[1]: ndindex(x,103)Out[1]:[4,0,3]
Für 1D-Arrays würde ich empfehlen np.flatnonzero(array == value)[0], was beiden entspricht np.nonzero(array == value)[0][0]und np.where(array == value)[0][0]die Hässlichkeit des Entpackens eines 1-Element-Tupels vermeidet.
Eine Alternative zur Auswahl 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 Überprüfung der Elemente des Arrays nach dem Auffinden der ersten Übereinstimmung beendet wird, während np.where alle Elemente auf Übereinstimmung überprüft. Ein Generatorausdruck wäre schneller, wenn es früh im Array eine Übereinstimmung gibt.
Für den Fall, dass das Array möglicherweise überhaupt nicht übereinstimmt, können Sie mit dieser Methode auch bequem einen Fallback-Wert angeben. Wenn das erste Beispiel Noneals Fallback zurückkehren würde, würde es werden next((i for i, x_i in enumerate(x) if x_i == 2), None).
Erlend Magnus Viggen
4
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önnen dann die ersten Elemente der Listen verwenden, um ein einzelnes Element zu erhalten.
Antworten:
Ja, hier ist die Antwort mit einem NumPy-Array
array
und einem Wertitem
, nach dem gesucht werden soll:Das Ergebnis ist ein Tupel mit zuerst allen Zeilenindizes und dann allen Spaltenindizes.
Wenn ein Array beispielsweise zwei Dimensionen hat und Ihr Element an zwei Stellen enthält, dann
wäre gleich Ihrem Artikel und so würde
numpy.where
quelle
rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
np.argwhere
wäre hier etwas nützlicher:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
where
funktioniert auf jedem Array und gibt ein Tupel der Länge 3 zurück, wenn es auf einem 3D-Array usw. verwendet wird.Wenn Sie den Index des ersten Auftretens nur eines Werts benötigen , können Sie Folgendes verwenden
nonzero
(oderwhere
, was in diesem Fall dasselbe bedeutet):Wenn Sie den ersten Index für jeden von vielen Werten benötigen , können Sie natürlich wiederholt dasselbe wie oben tun, aber es gibt einen Trick, der möglicherweise schneller ist. Im Folgenden werden die Indizes des ersten Elements jeder Teilsequenz ermittelt :
Beachten Sie, dass der Anfang beider Teilsequenzen von 3s und beider Teilsequenzen von 8s gefunden wird:
[ 1 , 1, 1, 2 , 2, 3 , 8 , 3 , 8 , 8]
Es ist also etwas anders als das erste zu finden Auftreten jedes Werts zu finden. In Ihrem Programm können Sie möglicherweise mit einer sortierten Version von arbeiten
t
, um das zu erhalten, was Sie möchten:quelle
r_
ist?r_
verkettet; oder genauer gesagt, es übersetzt Slice-Objekte in Verkettung entlang jeder Achse. Ich hättehstack
stattdessen verwenden können; das mag weniger verwirrend gewesen sein. Weitere Informationen finden Sie in der Dokumentationr_
. Es gibt auch einec_
.vals, locs = np.unique(t, return_index=True)
Sie können auch ein NumPy-Array in eine Liste in der Luft konvertieren und dessen Index abrufen. Zum Beispiel,
Es wird 1 gedruckt.
quelle
[find_list.index(index_list[i]) for i in range(len(index_list))]
find_list
in ein NumPy-Array vonobject
(oder etwas Spezifischerem, das angemessen ist) konvertieren und es einfach tunfind_arr[index_list]
.Nur um eine sehr performante und handliche hinzuzufügen numbaAlternative basierend auf
np.ndenumerate
, um den ersten Index zu finden:Dies ist ziemlich schnell und befasst sich natürlich mit mehrdimensionalen Arrays :
Dies kann viel schneller sein (weil es die Operation kurzschließt) als jeder Ansatz, der
np.where
oder verwendetnp.nonzero
.Allerdings
np.argwhere
könnte auch behandeln anmutig mit mehrdimensionalen Arrays (Sie würden müssen manuell in ein Tupel geworfen es und es ist nicht kurzgeschlossen) , aber es würde scheitern , wenn keine Übereinstimmung gefunden wird:quelle
@njit
ist eine Abkürzung vonjit(nopython=True)
dh die Funktion wird zum Zeitpunkt des ersten Durchlaufs im laufenden Betrieb vollständig kompiliert, sodass die Python-Interpreter-Aufrufe vollständig entfernt werden.Wenn Sie dies als Index für etwas anderes verwenden möchten, können Sie boolesche Indizes verwenden, wenn die Arrays sendbar sind. Sie benötigen keine expliziten Indizes. Der absolut einfachste Weg, dies zu tun, besteht darin, einfach basierend auf einem Wahrheitswert zu indizieren.
Jede boolesche Operation funktioniert:
Die Nicht-Null-Methode verwendet auch Boolesche Werte:
Die beiden Nullen stehen für das Tupel von Indizes (vorausgesetzt, first_array ist 1D) und dann für das erste Element im Array von Indizes.
quelle
l.index(x)
Gibt das kleinste i zurück , sodass i der Index des ersten Auftretens von x in der Liste ist.Man kann davon ausgehen, dass die
index()
Funktion in Python so implementiert ist, dass sie nach dem Finden der ersten Übereinstimmung stoppt, und dies führt zu einer optimalen Durchschnittsleistung.Verwenden Sie einen Iterator ( ndenumerate ) , um ein Element zu finden, das nach der ersten Übereinstimmung in einem NumPy-Array stoppt .
NumPy-Array:
Beachten Sie, dass beide Methoden
index()
undnext
einen Fehler zurückgeben, wenn das Element nicht gefunden wird. Mitnext
kann man ein zweites Argument verwenden, um einen speziellen Wert zurückzugeben, falls das Element nicht gefunden wird, zEs gibt auch andere Funktionen in NumPy (
argmax
,where
, undnonzero
) , die verwendet werden kann , ein Element in einem Array zu finden, aber sie haben alle den Nachteil , daß durch die ganze Reihe gehen auf der Suche nach allen Vorkommen, also nicht zum Auffinden des ersten Elements optimiert. Beachten Sie auch daswhere
undnonzero
geben Sie Arrays zurück, sodass Sie das erste Element auswählen müssen, um den Index abzurufen.Zeitvergleich
Wenn Sie nur überprüfen, ob bei großen Arrays die Lösung mithilfe eines Iterators schneller ist, wenn sich das gesuchte Element am Anfang des Arrays befindet (mithilfe
%timeit
der IPython-Shell):Dies ist ein offenes NumPy GitHub-Problem .
Siehe auch: Numpy: Finden Sie schnell den ersten Wertindex
quelle
%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))
? Wenn Sie sich fragen, warum es 1000-mal langsamer ist, dann deshalb, weil Python-Loops über numpy Arrays notorisch langsam sind.argmax
undwhere
in diesem Fall viel schneller sind (gesuchtes Element am Ende des Arrays)Für eindimensional sortierte Arrays wäre es viel einfacher und effizienter, O (log (n)) zu verwenden, indem numpy.searchsorted verwendet wird, das eine NumPy-Ganzzahl (Position) zurückgibt. Zum Beispiel,
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 sollen, um die Reihenfolge aufrechtzuerhalten.
quelle
Um nach Kriterien zu indizieren, können Sie so etwas wie das Folgende tun:
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.
quelle
Für 1D-Arrays würde ich empfehlen
np.flatnonzero(array == value)[0]
, was beiden entsprichtnp.nonzero(array == value)[0][0]
undnp.where(array == value)[0][0]
die Hässlichkeit des Entpackens eines 1-Element-Tupels vermeidet.quelle
Eine Alternative zur Auswahl des ersten Elements aus np.where () besteht darin, einen Generatorausdruck zusammen mit enumerate zu verwenden, z.
Für ein zweidimensionales Array würde man tun:
Der Vorteil dieses Ansatzes besteht darin, dass die Überprüfung der Elemente des Arrays nach dem Auffinden der ersten Übereinstimmung beendet wird, während np.where alle Elemente auf Übereinstimmung überprüft. Ein Generatorausdruck wäre schneller, wenn es früh im Array eine Übereinstimmung gibt.
quelle
None
als Fallback zurückkehren würde, würde es werdennext((i for i, x_i in enumerate(x) if x_i == 2), None)
.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:
Sie können dann die ersten Elemente der Listen verwenden, um ein einzelnes Element zu erhalten.
quelle
Das numpy_indexed- Paket (Haftungsausschluss, ich bin sein Autor) enthält ein vektorisiertes Äquivalent von list.index für numpy.ndarray; das ist:
Diese Lösung hat die Leistung vektorisiert, auf ndarrays verallgemeinert und bietet verschiedene Möglichkeiten, mit fehlenden Werten umzugehen.
quelle
Hinweis: Dies gilt für Python 2.7
Sie können eine Lambda-Funktion verwenden, um das Problem zu beheben. Sie funktioniert sowohl für das NumPy-Array als auch für die Liste.
Und du kannst verwenden
um den ersten Index der gefilterten Elemente zu erhalten.
Verwenden Sie für Python 3.6
anstatt
quelle
<filter object at 0x0000027535294D30>
zu Python 3 (getestet unter Python 3.6.3). Vielleicht Update für Python 3?