Was ist der effizienteste Weg, um zu überprüfen, ob ein Wert in einem NumPy-Array vorhanden ist?

73

Ich habe ein sehr großes NumPy-Array

1 40 3
4 50 4
5 60 7
5 49 6
6 70 8
8 80 9
8 72 1
9 90 7
.... 

Ich möchte überprüfen, ob in der ersten Spalte des Arrays ein Wert vorhanden ist. Ich habe eine Reihe von hausgemachten Methoden (z. B. Durchlaufen jeder Zeile und Überprüfen), aber angesichts der Größe des Arrays möchte ich die effizienteste Methode finden.

Vielen Dank!

thegreatt
quelle
1
Sie können die binäre Suche verwenden, wenn der 1. Index in nicht abnehmender Reihenfolge vorliegt, oder eine Sortierung in Betracht ziehen, wenn Sie mehr als beispielsweise 10 Suchvorgänge durchführen
Luka Rahne

Antworten:

73

Wie wäre es mit

if value in my_array[:, col_num]:
    do_whatever

Bearbeiten: Ich denke, __contains__ist so implementiert, dass dies die gleiche wie @ detlys Version ist

agf
quelle
9
Wissen Sie, ich habe mit numpy‚s - any()Funktion so stark vor kurzem habe ich über das gute alte völlig vergessen in.
Detly
9
Okay, das ist (a) besser lesbar und (b) ungefähr 40% schneller als meine Antwort.
Detly
5
Im Prinzip value in …kann dies schneller sein als any(… == value), da es über die Array-Elemente iterieren und anhalten kann, wenn der Wert angetroffen wird (anstatt zu berechnen, ob jedes Array-Element dem Wert entspricht, und dann zu überprüfen, ob eines der booleschen Ergebnisse wahr ist). .
Eric O Lebigot
1
@EOL wirklich? Ist in Python ein anyKurzschluss, nicht wahr numpy?
Agf
6
Die Dinge haben sich seitdem geändert. Beachten Sie, dass die Antwort von @ detly in Zukunft die einzige funktionierende Lösung sein wird. Derzeit wird eine Warnung ausgegeben. Weitere Informationen finden Sie unter stackoverflow.com/questions/40659212/… .
Borgr
48

Das offensichtlichste für mich wäre:

np.any(my_array[:, 0] == value)
detly
quelle
2
HI @detly können Sie weitere Erklärungen hinzufügen. es scheint dir sehr offensichtlich, aber ein Anfänger wie ich ist es nicht. Mein Instinkt sagt mir, dass dies die Lösung sein könnte, nach der ich suche, aber ich konnte es nicht ohne Beispiele versuchen: D
Jameshwart Lopez
@jameshwartlopez my_array[:, 0]gibt Ihnen alle Zeilen (angezeigt durch :) und für jede Zeile das 0th-Element, dh die erste Spalte. Dies ist beispielsweise ein einfaches eindimensionales Array [1, 3, 6, 2, 9]. Wenn Sie den ==Operator in numpy mit einem Skalar verwenden, führt er einen elementweisen Vergleich durch und gibt ein boolesches numpy-Array mit derselben Form wie das Array zurück. Also [1, 3, 6, 2, 9] == 3gibt [False, True, False, False, False]. Schließlich np.anyprüft, ob alle Werte in diesem Array sind True.
Kilian Batzner
42

Um mehrere Werte zu überprüfen, können Sie numpy.in1d ​​() verwenden, eine elementweise Funktionsversion des Python-Schlüsselworts in. Wenn Ihre Daten sortiert sind, können Sie numpy.searchsorted () verwenden:

import numpy as np
data = np.array([1,4,5,5,6,8,8,9])
values = [2,3,4,6,7]
print np.in1d(values, data)

index = np.searchsorted(data, values)
print data[index] == values
HYRY
quelle
3
+1 für die weniger bekannten numpy.in1d()und für die sehr schnellen searchsorted().
Eric O Lebigot
@eryksun: Ja, interessant. Gleiche Beobachtung hier ...
Eric O Lebigot
1
Beachten Sie, dass die letzte Zeile ein IndexErrorElement auslöst, das valuesgrößer als der größte Wert von ist data, sodass besondere Aufmerksamkeit erforderlich ist.
Fuglede
@fuglede Es ist möglich , zu ersetzen , indexmit index % len(data)oder np.append(index[:-1],0)äquivalent in diesem Fall.
Mathfux
18

Faszinierend. Ich musste die Geschwindigkeit einer Reihe von Schleifen verbessern, die auf dieselbe Weise eine Matching-Index-Bestimmung durchführen müssen. Also habe ich beschlossen, alle Lösungen hier zusammen mit einigen Riffs zu planen.

Hier sind meine Geschwindigkeitstests für Python 2.7.10:

import timeit
timeit.timeit('N.any(N.in1d(sids, val))', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

18.86137104034424

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = [20010401010101+x for x in range(1000)]')

15.061666011810303

timeit.timeit('N.in1d(sids, val)', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

11.613027095794678

timeit.timeit('N.any(val == sids)', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

7.670552015304565

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

5.610057830810547

timeit.timeit('val == sids', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')

1.6632978916168213

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = set([20010401010101+x for x in range(1000)])')

0,0548710823059082

timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = dict(zip([20010401010101+x for x in range(1000)],[True,]*1000))')

0,054754018783569336

Sehr überraschend! Größenordnungsunterschiede!

Zusammenfassend lässt sich sagen, ob Sie nur wissen möchten, ob sich etwas in einer 1D-Liste befindet oder nicht:

  • 19s N.any (N.in1d ​​(Numpy Array))
  • 15s x in (Liste)
  • 8s N.any (x == numpy Array)
  • 6s x in (numpy Array)
  • .1s x in (Set oder ein Wörterbuch)

Wenn Sie auch wissen möchten, wo sich etwas in der Liste befindet (Reihenfolge ist wichtig):

  • 12s N.in1d ​​(x, numpy Array)
  • 2s x == (numpy Array)
Lukas Mandrake
quelle
1

Das Hinzufügen zu @ HYRYs Antwort in1d scheint für numpy am schnellsten zu sein. Dies verwendet Numpy 1.8 und Python 2.7.6.

In diesem Test war in1d am schnellsten:

a = arange(0,99999,3)
%timeit 10 in a
%timeit in1d(a, 10)

10000 loops, best of 3: 150 µs per loop
10000 loops, best of 3: 61.9 µs per loop

Die Verwendung eines Python-Sets scheint am schnellsten zu sein:

s = set(range(0, 99999, 3))
%timeit 10 in s

10000000 loops, best of 3: 47 ns per loop
Joelmob
quelle
1
Der Vergleich ist nicht fair. Sie müssen die Kosten für die Konvertierung eines Arrays in ein Array zählen set. OP beginnt mit einem NumPy-Array.
Jpp
0

Der meiner Meinung nach bequemste Weg ist:

(Val in X[:, col_num])

Dabei ist Val der Wert, nach dem Sie suchen möchten, und X das Array. Angenommen, Sie möchten in Ihrem Beispiel überprüfen, ob der Wert 8 in Ihrer dritten Spalte vorhanden ist. Einfach schreiben

(8 in X[:, 2])

Dies gibt True zurück, wenn 8 in der dritten Spalte steht, andernfalls False.

Loochie
quelle