Wie funktioniert python numpy.where ()?


94

Ich spiele mit numpyund stöbere in der Dokumentation und bin auf etwas Magie gestoßen. Ich spreche nämlich von numpy.where():

>>> x = np.arange(9.).reshape(3, 3)
>>> np.where( x > 5 )
(array([2, 2, 2]), array([0, 1, 2]))

Wie erreichen sie intern, dass Sie so etwas x > 5in eine Methode überführen können? Ich denke, es hat etwas damit zu tun, __gt__aber ich suche nach einer detaillierten Erklärung.

Antworten:


75

Wie erreichen sie intern, dass Sie so etwas wie x> 5 an eine Methode übergeben können?

Die kurze Antwort ist, dass sie es nicht tun.

Jede Art von logischer Operation für ein Numpy-Array gibt ein boolesches Array zurück. (dh __gt__, __lt__usw., alle geben boolesche Arrays zurück, bei denen die angegebene Bedingung erfüllt ist).

Z.B

x = np.arange(9).reshape(3,3)
print x > 5

Ausbeuten:

array([[False, False, False],
       [False, False, False],
       [ True,  True,  True]], dtype=bool)

Dies ist der gleiche Grund, warum so etwas wie if x > 5:ein ValueError ausgelöst wird, wenn xes sich um ein Numpy-Array handelt. Es ist ein Array von True / False-Werten, kein einzelner Wert.

Darüber hinaus können Numpy-Arrays durch Boolesche Arrays indiziert werden. ZB x[x>5]ergibt [6 7 8]in diesem Fall.

Ehrlich gesagt ist es ziemlich selten, dass Sie tatsächlich benötigen, numpy.whereaber es gibt nur die Angaben zurück, wo sich ein boolesches Array befindet True. Normalerweise können Sie mit einer einfachen booleschen Indizierung das tun, was Sie brauchen.


10
Nur darauf hinweist, dass numpy.where2 ‚Betriebsart‘ hat, erste kehrt die indices, wo condition is Trueund wenn optionale Parameter xund yvorhanden ist (gleiche Form wie conditionoder sende solche Form!), Es wird wieder Werte aus , xwenn condition is Truenicht anders aus y. Dies macht wherees vielseitiger und ermöglicht eine häufigere Verwendung. Danke
essen

1
In einigen Fällen kann es auch zu Overhead kommen, wenn die __getitem__Syntax von []over entweder numpy.whereoder verwendet wird numpy.take. Da __getitem__auch das Schneiden unterstützt werden muss, gibt es etwas Overhead. Ich habe bemerkenswerte Geschwindigkeitsunterschiede festgestellt, als ich mit den Python Pandas-Datenstrukturen gearbeitet und sehr große Spalten logisch indiziert habe. In diesen Fällen, wenn Sie kein Schneiden benötigen, dann takeund wheresind tatsächlich besser.
ely

24

Alte Antwort, es ist irgendwie verwirrend. Es gibt Ihnen die STANDORTE (alle), an denen Ihre Aussage wahr ist.

so:

>>> a = np.arange(100)
>>> np.where(a > 30)
(array([31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
       48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
       65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
       82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
       99]),)
>>> np.where(a == 90)
(array([90]),)

a = a*40
>>> np.where(a > 1000)
(array([26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
       43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
       60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
       77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
       94, 95, 96, 97, 98, 99]),)
>>> a[25]
1000
>>> a[26]
1040

Ich benutze es als Alternative zu list.index (), aber es hat auch viele andere Verwendungszwecke. Ich habe es noch nie mit 2D-Arrays verwendet.

http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html

Neue Antwort Es scheint, dass die Person etwas grundlegenderes gefragt hat.

Die Frage war, wie SIE etwas implementieren können, das es einer Funktion (z. B. wo) ermöglicht, zu wissen, was angefordert wurde.

Beachten Sie zunächst, dass das Aufrufen eines der Vergleichsoperatoren eine interessante Sache ist.

a > 1000
array([False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True`,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)`

Dies erfolgt durch Überladen der Methode "__gt__". Zum Beispiel:

>>> class demo(object):
    def __gt__(self, item):
        print item


>>> a = demo()
>>> a > 4
4

Wie Sie sehen können, war "a> 4" ein gültiger Code.

Eine vollständige Liste und Dokumentation aller überladenen Funktionen finden Sie hier: http://docs.python.org/reference/datamodel.html

Unglaublich ist, wie einfach das geht. ALLE Operationen in Python werden so ausgeführt. A> b zu sagen ist gleichbedeutend mit a. gt (b)!


3
Diese Überladung von Vergleichsoperatoren scheint jedoch mit komplexeren logischen Ausdrücken nicht gut zu funktionieren - zum Beispiel kann ich das nicht np.where(a > 30 and a < 50)oder np.where(30 < a < 50)weil sie letztendlich versucht, das logische UND von zwei Arrays von Booleschen Werten zu bewerten, was ziemlich bedeutungslos ist. Gibt es eine Möglichkeit, eine solche Bedingung mit zu schreiben np.where?
DavidA

@ Meowsqueaknp.where((a > 30) & (a < 50))
Tibalt

Warum gibt np.where () in Ihrem Beispiel eine Liste zurück?
Andreas Yankopolus

0

np.where Gibt ein Tupel mit einer Länge zurück, die der Dimension des numpy ndarray entspricht, auf dem es aufgerufen wird (mit anderen Worten ndim ), und jedes Tupelelement ist ein Numpy-Ndarray mit Indizes aller Werte im Anfangs-Ndarray, für die die Bedingung True ist. (Bitte verwechseln Sie Dimension nicht mit Form)

Beispielsweise:

x=np.arange(9).reshape(3,3)
print(x)
array([[0, 1, 2],
      [3, 4, 5],
      [6, 7, 8]])
y = np.where(x>4)
print(y)
array([1, 2, 2, 2], dtype=int64), array([2, 0, 1, 2], dtype=int64))


y ist ein Tupel der Länge 2, weil x.ndim es ist. Das erste Element im Tupel enthält Zeilennummern aller Elemente größer als 4 und das zweite Element enthält Spaltennummern aller Elemente größer als 4. Wie Sie sehen können, [1,2,2 , 2] entspricht Zeilennummern von 5,6,7,8 und [2,0,1,2] entspricht Spaltennummern von 5,6,7,8. Beachten Sie, dass der ndarray entlang der ersten Dimension (zeilenweise) durchlaufen wird ).

Ähnlich,

x=np.arange(27).reshape(3,3,3)
np.where(x>4)


gibt ein Tupel der Länge 3 zurück, da x 3 Dimensionen hat.

Aber warte, es gibt noch mehr zu np.where!

wenn zwei zusätzliche Argumente hinzugefügt werden np.where; Es wird eine Ersetzungsoperation für alle paarweisen Zeilen-Spalten-Kombinationen ausgeführt, die durch das obige Tupel erhalten werden.

x=np.arange(9).reshape(3,3)
y = np.where(x>4, 1, 0)
print(y)
array([[0, 0, 0],
   [0, 0, 1],
   [1, 1, 1]])
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.