2016-06-08 14 views
3

Warum ist es, in Python/numpy:Python numpy seltsames boolean arithmetisches Verhaltens

from numpy import asarray 
bools=asarray([False,True]) 

print(bools) 
[False True] 

print(1*bools, 0+bools, 0-bools) # False, True are valued as 0, 1 
[0 1] [0 1] [ 0 -1] 

print(-2*bools, -bools*2)   # !? expected same result! :-/ 
[0 -2] [2 0] 

print(-bools)      # this is the reason! 
[True False] 

Ich halte es seltsam, dass -bools kehrt logical_not(bools), weil in allen anderen Fällen das Verhalten "Arithmetik", nicht "logisch" .

Einer, der eine Reihe von booleans als 0/1 Maske (oder „charakteristische Funktion“) verwenden möchte irgendwie Evolvente Ausdrücke zu verwenden, gezwungen wird, wie (0-bools) oder (-1)*bools und in Fehler leicht entstehen kann, wenn er darüber vergisst .

Warum ist es so, und was wäre der beste akzeptable Weg, um das gewünschte Verhalten zu erreichen? (neben dem Kommentar natürlich)

+1

Ich sehe nicht, warum jemand eine Reihe von Booleans für eine Maske und nicht (0,1) verwenden würde, die viel intuitiver ist, aber ich sehe einen Punkt. Was ist das gewünschte Verhalten, wenn man -2 * Falsch ?? –

+0

+ In Python ist auch alles logisch. wie in "blabla" ist True (also irgendwie boolean) und eine Zeichenfolge zur gleichen Zeit. –

+0

@ Ev.Kounis, ich stolperte hinein, als ich mit dem folgenden Code einen verzögerten exponentiellen Zerfall schreiben wollte: delExpDecay = Lambda t, d, a, tau: a * exp (- (t lurix66

Antwort

2

Es dreht sich alles um die Reihenfolge der Operatoren und Datentypen.

>>> import numpy as np 
>>> B = np.array([0, 1], dtype=np.bool) 
>>> B 
array([False, True], dtype=bool) 

Mit numpy werden boolesche Arrays als boolesche Arrays behandelt. Jede Operation, die auf sie angewendet wird, versucht zunächst, den Datentyp beizubehalten. Das ist so:

>>> -B 
array([ True, False], dtype=bool) 

und

>>> ~B 
array([ True, False], dtype=bool) 

, die äquivalent sind, kehren die elementweise Negation ihrer Elemente. Beachten Sie jedoch, dass die Verwendung von -B eine Warnung auslöst, da die Funktion veraltet ist.

Wenn Sie Dinge wie:

>>> B + 1 
array([1, 2]) 

B und 1 werden zunächst unter der Haube auf den gleichen Datentyp gecastet. Bei Daten-Promotions wird das Array boolean immer in ein numeric Array geworfen. In dem obigen Fall wird B zu int gegossen, die als ähnlich ist:

>>> B.astype(int) + 1 
array([1, 2]) 

In Ihrem Beispiel:

>>> -B * 2 
array([2, 0]) 

Zuerst wird das Array B durch den Bediener negiert wird - und dann mit 2 multipliziert.Das gewünschte Verhalten kann durch explizite Datenkonvertierung angenommen entweder, oder Klammern hinzugefügt ordnungsgemäßen Betrieb zu gewährleisten:

>>> -(B * 2) 
array([ 0, -2]) 

oder

>>> -B.astype(int) * 2 
array([ 0, -2]) 

Beachten Sie, dass B.astype(int) durch B.view(np.int8) ohne Daten-Kopie ersetzt werden, wie Boolesche Werte werden durch characters repräsentiert und haben somit 8 Bits, die Daten können als ganze Zahlen mit der .view Methode betrachtet werden, ohne sie konvertieren zu müssen.

>>> B.view(np.int8) 
array([0, 1], dtype=int8) 

Also, kurz gesagt, B.view(np.int8) oder B.astype(yourtype) immer ensurs dass B ein [0,1] numerisches Array ist.

+0

Vielen Dank für die ausführliche Erklärung und vor allem für die Tilde '~'. Wenn wir einen Tildeoperator haben, warum sollte das unäre Minuszeichen "-" als Duplikat funktionieren? Ich würde es eher als logisch betrachten, dass sowohl das unäre plus '+' als auch das unäre minus '-' eine arithmetische Umwandlung erzeugen, wie sie es in Operationen wie '0 + B' oder '0-B' tun. (Siehe auch meinen Kommentar zu meiner eigenen Frage oben) – lurix66

+0

@ lurix66 Es ist nur eine Design-Entscheidung, und anscheinend bedauern sie es, da es veraltet ist und in Zukunft entfernt werden wird. Wenn Sie '-' als binären Operator' 0-B' oder 'B-0' verwenden, funktioniert das Problem (wie erwartet), wenn Sie' -' als unären Operator '-B' verwenden in "-1 * B" übersetzt werden, wie in numerischen Arrays, wird es übersetzt in "~ B" (oder "nicht B"). Wiederum können wir nichts tun, bis numpy sich entscheidet, den '-'-unären Operator nicht mehr als Negationsoperator zu unterstützen, also müssen wir entweder warten oder vorsichtiger sein: P –

0

Numpy-Arrays sind homogen - alle Elemente haben den gleichen Typ für ein gegebenes Array, und das Array-Objekt speichert welchen Typ das ist. Wenn Sie ein Array mit True und False erstellen, handelt es sich um ein Array vom Typ bool, und Operatoren verhalten sich auf dem Array als solche. Es ist daher nicht verwunderlich, dass logische Verneinung in Situationen auftritt, die eine logische Negation für eine normale bool wären. Wenn Sie die Arrays für Ganzzahlmathematik verwenden, werden sie in 1 und 0 konvertiert. Von all Ihren Beispielen sind dies die anomaleren Fälle, dh das Verhalten, auf das Sie sich bei gutem Code nicht verlassen sollten.

Wie in den Kommentaren vorgeschlagen, wenn Sie Mathe mit einem Array von Nullen und Einsen machen möchten, ist es besser, nur ein Array von Nullen und Einsen zu machen. Je nachdem, was Sie damit tun möchten, können Sie sich jedoch besser mit Funktionen wie numpy.where() vertraut machen.

+0

(siehe meine Kommentare zu vorherigen Fragen), halte ich Liner für wertvoll, wenn sie einfach sind. Die Verwendung von 'numpy.where()' sieht für mich weniger einfach aus, als mit der normalerweise offensichtlichen Äquivalenz, dass ein boolescher Maskenwert 1 ist, wobei True und 0 mit False übereinstimmen. – lurix66