Was erklärt den Unterschied im Verhalten von booleschen und bitweisen Operationen in Listen gegenüber NumPy-Arrays?
Ich bin verwirrt über die angemessene Verwendung von &
vs and
in Python, die in den folgenden Beispielen veranschaulicht wird.
mylist1 = [True, True, True, False, True]
mylist2 = [False, True, False, True, False]
>>> len(mylist1) == len(mylist2)
True
# ---- Example 1 ----
>>> mylist1 and mylist2
[False, True, False, True, False]
# I would have expected [False, True, False, False, False]
# ---- Example 2 ----
>>> mylist1 & mylist2
TypeError: unsupported operand type(s) for &: 'list' and 'list'
# Why not just like example 1?
>>> import numpy as np
# ---- Example 3 ----
>>> np.array(mylist1) and np.array(mylist2)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# Why not just like Example 4?
# ---- Example 4 ----
>>> np.array(mylist1) & np.array(mylist2)
array([False, True, False, False, False], dtype=bool)
# This is the output I was expecting!
Diese Antwort und diese Antwort haben mir geholfen zu verstehen, dass and
es sich um eine boolesche Operation handelt, aber &
um eine bitweise Operation.
Ich habe über bitweise Operationen gelesen, um das Konzept besser zu verstehen, aber ich habe Schwierigkeiten, diese Informationen zu verwenden, um meine obigen 4 Beispiele zu verstehen.
Beispiel 4 führte mich zu meiner gewünschten Ausgabe, das ist in Ordnung, aber ich bin immer noch verwirrt darüber, wann / wie / warum ich and
vs verwenden sollte &
. Warum verhalten sich Listen und NumPy-Arrays bei diesen Operatoren unterschiedlich?
Kann mir jemand helfen, den Unterschied zwischen booleschen und bitweisen Operationen zu verstehen, um zu erklären, warum sie Listen und NumPy-Arrays unterschiedlich behandeln?
np.bitwise_and()
undnp.logical_and()
und Freunde, um Verwirrung zu vermeiden.mylist1 and mylist2
wird nicht das gleiche Ergebnis ausgegeben wiemylist2 and mylist1
, da die zweite Liste zurückgegeben wird, auf die delnan hingewiesen hat.Antworten:
and
testet, ob beide Ausdrücke logisch sind,True
während&
(wenn mitTrue
/False
values verwendet) getestet wird, ob beide logisch sindTrue
.In Python werden leere integrierte Objekte normalerweise als logisch behandelt,
False
während nicht leere integrierte Objekte logisch sindTrue
. Dies erleichtert den allgemeinen Anwendungsfall, in dem Sie etwas tun möchten, wenn eine Liste leer ist, und etwas anderes, wenn die Liste nicht leer ist. Beachten Sie, dass dies bedeutet, dass die Liste [False] logisch istTrue
:In Beispiel 1 ist die erste Liste also nicht leer und daher logisch
True
, sodass der Wahrheitswert vonand
der gleiche ist wie der der zweiten Liste. (In unserem Fall ist die zweite Liste nicht leer und daher logischTrue
, aber die Identifizierung würde einen unnötigen Berechnungsschritt erfordern.)Zum Beispiel 2 können Listen nicht sinnvoll bitweise kombiniert werden, da sie beliebige Elemente enthalten können. Zu den Dingen, die bitweise kombiniert werden können, gehören: Trues und Falses, ganze Zahlen.
Im Gegensatz dazu unterstützen NumPy-Objekte vektorisierte Berechnungen. Das heißt, Sie können dieselben Vorgänge für mehrere Daten ausführen.
Beispiel 3 schlägt fehl, weil NumPy-Arrays (mit einer Länge> 1) keinen Wahrheitswert haben, da dies eine vektorbasierte logische Verwirrung verhindert.
Beispiel 4 ist einfach eine vektorisierte Bitoperation
and
.Endeffekt
Wenn Sie sich nicht mit Arrays beschäftigen und keine mathematischen Manipulationen von ganzen Zahlen durchführen, möchten Sie wahrscheinlich
and
.Wenn Sie Vektoren von Wahrheitswerten haben, die Sie kombinieren möchten, verwenden Sie
numpy
mit&
.quelle
Über
list
Zunächst ein sehr wichtiger Punkt, von dem aus alles folgen wird (hoffe ich).
In gewöhnlichem Python
list
ist es in keiner Weise etwas Besonderes (außer eine niedliche Syntax zum Konstruieren zu haben, was meistens ein historischer Unfall ist). Sobald eine Liste[3,2,6]
erstellt wurde, handelt es sich in jeder Hinsicht nur um ein gewöhnliches Python-Objekt, z. B. eine Zahl3
, eine Menge{3,7}
oder eine Funktionlambda x: x+5
.(Ja, es unterstützt das Ändern seiner Elemente und es unterstützt die Iteration und viele andere Dinge, aber genau das ist ein Typ: Es unterstützt einige Operationen, während andere nicht unterstützt werden. Int unterstützt das Erhöhen auf eine Potenz, aber das tut es nicht mach es zu etwas ganz Besonderem - es ist genau das, was ein Int ist. Lambda unterstützt das Aufrufen, aber das macht es nicht zu etwas Besonderem - dafür ist Lambda schließlich :).
Über
and
and
ist kein Operator (Sie können es "Operator" nennen, aber Sie können auch "für" einen Operator nennen :). Operatoren in Python sind (implementiert durch) Methoden, die für Objekte eines Typs aufgerufen werden und normalerweise als Teil dieses Typs geschrieben werden. Es gibt keine Möglichkeit für eine Methode, eine Auswertung einiger ihrer Operanden durchzuführen, aber sieand
kann (und muss) dies tun.Die Folge davon ist, dass
and
nicht überladen werden kann, genauso wiefor
nicht überladen werden kann. Es ist vollständig allgemein und kommuniziert über ein bestimmtes Protokoll. Was Sie tun können , ist Ihren Teil des Protokolls anzupassen, aber das bedeutet nicht, dass Sie das Verhalten vonand
vollständig ändern können . Das Protokoll lautet:Stellen Sie sich vor, Python interpretiert "a und b" (dies geschieht nicht wörtlich auf diese Weise, aber es hilft beim Verständnis). Wenn es um "und" geht, betrachtet es das Objekt, das es gerade ausgewertet hat (a), und fragt es: Sind Sie wahr? ( NICHT : bist du
True
?) Wenn du ein Autor der Klasse von a bist, kannst du diese Antwort anpassen. Wenn diea
Antwort "nein"and
lautet (b wird vollständig übersprungen, wird es überhaupt nicht ausgewertet und) lautet:a
ist mein Ergebnis ( NICHT : Falsch ist mein Ergebnis).Wenn
a
nicht antwortet,and
fragt es: Wie lang sind Sie? (Auch hier können Sie dies als Autor dera
Klasse anpassen .) Wenn diea
Antwort 0 lautet,and
wird dasselbe wie oben ausgeführt - betrachtet sie als falsch ( NICHT falsch), überspringt b und gibta
als Ergebnis.Wenn
a
die zweite Frage mit etwas anderem als 0 beantwortet wird ("Was ist Ihre Länge?") Oder wenn die erste Frage überhaupt nicht beantwortet wird oder wenn die erste Frage mit "Ja" beantwortet wird (" Sind Sie wahr?"),and
Wird b und bewertet sagt:b
ist mein Ergebnis. Beachten Sie, dass es sich nicht fragenb
Fragen.Die andere Art, dies alles zu sagen,
a and b
ist fast die gleiche wieb if a else a
, außer dass a nur einmal ausgewertet wird.Setzen Sie sich nun ein paar Minuten mit Stift und Papier hin und überzeugen Sie sich selbst, dass {a, b}, wenn es sich um eine Teilmenge von {True, False} handelt, genau so funktioniert, wie Sie es von Booleschen Operatoren erwarten würden. Aber ich hoffe, ich habe Sie davon überzeugt, dass es viel allgemeiner und, wie Sie sehen werden, auf diese Weise viel nützlicher ist.
Diese beiden zusammenfügen
Jetzt hoffe ich, dass Sie Ihr Beispiel verstehen 1.
and
Es ist mir egal, ob mylist1 eine Zahl, eine Liste, ein Lambda oder ein Objekt einer Klasse Argmhbl ist. Es geht nur um die Antwort von mylist1 auf die Fragen des Protokolls. Und natürlich beantwortet mylist1 5 auf die Frage nach der Länge, also gibt mylist2 zurück. Und das ist es. Es hat nichts mit Elementen von mylist1 und mylist2 zu tun - sie kommen nirgendwo ins Bild.Zweites Beispiel:
&
einlist
Auf der anderen Seite
&
ist ein Operator wie jeder andere, wie+
zum Beispiel. Sie kann für einen Typ definiert werden, indem eine spezielle Methode für diese Klasse definiert wird.int
definiert es als bitweise "und" und bool definiert es als logisch "und", aber das ist nur eine Option: Zum Beispiel definieren Mengen und einige andere Objekte wie Diktatschlüsselansichten es als Mengenschnittstelle.list
definiert es einfach nicht, wahrscheinlich weil Guido sich keine offensichtliche Art der Definition ausgedacht hat.numpy
Auf der anderen Seite: -D, numpy Arrays sind etwas Besonderes oder versuchen es zumindest. Natürlich ist numpy.array nur eine Klasse, sie kann
and
in keiner Weise überschrieben werden, also macht sie das nächstbeste: Wenn sie gefragt werden, ob Sie wahr sind, löst numpy.array einen ValueError aus und sagt effektiv: "Bitte formulieren Sie die Frage neu, meine." Sicht der Wahrheit passt nicht in Ihr Modell ". (Beachten Sie, dass in der ValueError-Nachricht nicht gesprochen wird,and
da numpy.array nicht weiß, wer die Frage stellt. Sie spricht nur über die Wahrheit.)Denn
&
es ist eine ganz andere Geschichte. numpy.array kann es so definieren, wie es möchte, und es definiert&
konsistent mit anderen Operatoren: pointwise. So bekommen Sie endlich, was Sie wollen.HTH,
quelle
Die kurzgeschlossenen booleschen Operatoren (
and
,or
) können nicht überschrieben werden, da es keinen zufriedenstellenden Weg gibt, dies zu tun, ohne neue Sprachfunktionen einzuführen oder Kurzschlüsse zu opfern. Wie Sie vielleicht wissen oder nicht wissen, bewerten sie den ersten Operanden auf seinen Wahrheitswert. Abhängig von diesem Wert bewerten sie entweder das zweite Argument und geben es zurück oder geben das zweite Argument nicht aus und geben das erste zurück:Beachten Sie, dass der (Ergebnis der Auswertung des) tatsächlichen Operanden zurückgegeben wird, nicht der Wahrheitswert.
Die einzige Möglichkeit, ihr Verhalten anzupassen, besteht darin, es zu überschreiben
__nonzero__
(__bool__
in Python 3 umbenannt), damit Sie beeinflussen können, welcher Operand zurückgegeben wird, aber nichts anderes zurückgeben. Listen (und andere Sammlungen) werden als "wahr" definiert, wenn sie überhaupt etwas enthalten, und als "falsch", wenn sie leer sind.NumPy-Arrays lehnen diesen Gedanken ab: Für die Anwendungsfälle, auf die sie abzielen, sind zwei verschiedene Vorstellungen von Wahrheit üblich: (1) ob ein Element wahr ist und (2) ob alle Elemente wahr sind. Da diese beiden vollständig (und stillschweigend) inkompatibel sind und weder eindeutig korrekter noch häufiger vorkommen, weigert sich NumPy zu raten und verlangt, dass Sie explizit
.any()
oder verwenden.all()
.&
und|
(undnot
übrigens) können vollständig außer Kraft gesetzt werden, da sie nicht kurzschließen. Sie können beim Überschreiben überhaupt alles zurückgeben, und NumPy nutzt dies gut, um elementweise Operationen durchzuführen, wie dies bei praktisch jeder anderen skalaren Operation der Fall ist. Listen hingegen senden keine Vorgänge über ihre Elemente hinweg. So wiemylist1 - mylist2
es nichts bedeutet undmylist1 + mylist2
etwas völlig anderes bedeutet, gibt es keinen&
Operator für Listen.quelle
[False] or [True]
Bewertung von[False]
und die[False] and [True]
Bewertung von[True]
.Beispiel 1:
So funktioniert der Operator und .
x und y => wenn x falsch ist, dann x , sonst y
Mit anderen Worten, da dies
mylist1
nichtFalse
der Fall ist , ist das Ergebnis des Ausdrucksmylist2
. (Nur leere Listen werden ausgewertetFalse
.)Beispiel 2:
Der
&
Operator ist für eine bitweise und, wie Sie erwähnen. Bitweise Operationen funktionieren nur mit Zahlen. Das Ergebnis von a & b ist eine Zahl, die aus 1s in Bits besteht, die sowohl in a als auch in b 1 sind . Beispielsweise:Mit einem binären Literal (gleiche Zahlen wie oben) ist es einfacher zu sehen, was passiert :
Bitweise Operationen ähneln im Konzept booleschen (Wahrheits-) Operationen, funktionieren jedoch nur mit Bits.
Also, ein paar Aussagen über mein Auto gegeben
Das logische "und" dieser beiden Aussagen lautet:
Beides gilt zumindest für mein Auto. Der Wert der Aussage als Ganzes ist also logisch wahr.
Das bitweise "und" dieser beiden Aussagen ist etwas nebulöser:
Wenn Python weiß, wie die Anweisungen in numerische Werte konvertiert werden, wird es dies tun und das bitweise und der beiden Werte berechnen. Dies mag dazu führen, dass Sie glauben, dass dies
&
austauschbar istand
, aber wie im obigen Beispiel handelt es sich um verschiedene Dinge. Für die Objekte, die nicht konvertiert werden können, erhalten Sie lediglich eineTypeError
.Beispiel 3 und 4:
Numpy implementiert arithmetische Operationen für Arrays:
Implementiert jedoch keine logischen Operationen für Arrays, da Sie logische Operatoren in Python nicht überladen können . Deshalb funktioniert Beispiel drei nicht, Beispiel vier jedoch.
Um Ihre
and
vs-&
Frage zu beantworten : Verwenden Sieand
.Die bitweisen Operationen werden verwendet, um die Struktur einer Zahl zu untersuchen (welche Bits gesetzt sind, welche Bits nicht gesetzt sind). Diese Art von Informationen wird hauptsächlich in Betriebssystemschnittstellen auf niedriger Ebene verwendet ( z. B. Unix-Berechtigungsbits ). Die meisten Python-Programme müssen das nicht wissen.
Die logischen Operationen (
and
,or
,not
), jedoch sind die ganze Zeit verwendet.quelle
In Python ein Ausdruck von
X and Y
RückgabenY
, vorausgesetzt, dassbool(X) == True
oder einer vonX
oderY
zu False ausgewertet wird, z.Der bitweise Operator ist für Listen einfach nicht definiert. Es ist jedoch für Ganzzahlen definiert, die über die binäre Darstellung der Zahlen arbeiten. Betrachten Sie 16 (01000) und 31 (11111):
NumPy ist keine psychische, weiß er nicht, ob Sie bedeuten , dass zB
[False, False]
sollte gleichTrue
in einem logischen Ausdruck. Dabei wird ein Standard-Python-Verhalten überschrieben, das lautet: "Jede leere Sammlung mitlen(collection) == 0
isFalse
".Wahrscheinlich ein erwartetes Verhalten von NumPys Arrays & Operator.
quelle
Für das erste Beispiel und basierend auf dem Django-Dokument
wird immer die zweite Liste zurückgegeben. In der Tat wird eine nicht leere Liste als True-Wert für Python angesehen. Python gibt also den 'letzten' True-Wert zurück, also die zweite Liste
quelle
Operationen mit einer Python-Liste arbeiten mit der Liste .
list1 and list2
prüft, oblist1
es leer ist, und gibt zurück,list1
ob es leer ist undlist2
ob es nicht ist.list1 + list2
anhängenlist2
zulist1
, so dass Sie eine neue Liste mit bekommenlen(list1) + len(list2)
Elementen.Operatoren, die nur dann sinnvoll sind, wenn sie elementweise angewendet werden, z. B.
&
erhöhen Sie aTypeError
, da elementweise Operationen nicht unterstützt werden, ohne die Elemente zu durchlaufen.Numpy Arrays unterstützen elementweise Operationen.
array1 & array2
berechnet das bitweise oder für jedes entsprechende Element inarray1
undarray2
.array1 + array2
berechnet die Summe für jedes entsprechende Element inarray1
undarray2
.Dies funktioniert nicht für
and
undor
.array1 and array2
ist im Wesentlichen eine Abkürzung für den folgenden Code:Dafür benötigen Sie eine gute Definition von
bool(array1)
. Für globale Operationen, wie sie in Python-Listen verwendet werden, lautet die Definition,bool(list) == True
wenn sielist
nicht leer sind undFalse
wenn sie leer sind. Bei den elementweisen Operationen von numpy besteht eine gewisse Unklarheit darüber, ob geprüft werden soll, ob ein Element ausgewertetTrue
wird oder ob alle Elemente ausgewertet werdenTrue
. Da beide wohl korrekt sind, errät numpy nicht und löst einValueError
Wann aus,bool()
das (indirekt) für ein Array aufgerufen wird.quelle
Gute Frage. Ähnlich wie bei der Beobachtung, die Sie zu den Beispielen 1 und 4 (oder sollte ich 1 & 4 sagen :)) über logische
and
bitweise&
Operatoren gemacht haben, habe ich Erfahrungen mitsum
Operatoren gemacht. Numpysum
und Pysum
verhalten sich ebenfalls unterschiedlich. Beispielsweise:Angenommen, "mat" ist ein numpy 5x5 2d-Array wie:
Dann gibt numpy.sum (mat) die Gesamtsumme der gesamten Matrix an. Während die in Python integrierte Summe wie sum (mat) nur entlang der Achse summiert. Siehe unten:
quelle