Wie kann ich das elementweise logische NICHT einer Pandas-Serie erhalten?

229

Ich habe ein Pandas- SeriesObjekt, das boolesche Werte enthält. Wie kann ich eine Reihe erhalten, die die Logik NOTjedes Werts enthält?

Stellen Sie sich zum Beispiel eine Reihe vor, die Folgendes enthält:

True
True
True
False

Die Serie, die ich bekommen möchte, würde enthalten:

False
False
False
True

Dies scheint einigermaßen einfach zu sein, aber anscheinend habe ich mein Mojo verlegt = (

blz
quelle
1
Es ist wichtig, dass die Daten keine objectTypen enthalten , damit die folgenden Antworten funktionieren. Verwenden Sie daher:~ df.astype('bool')
LearnOPhile
Ich habe über alle logischen Operatoren in diesem Beitrag geschrieben . Der Beitrag enthält auch Alternativen.
CS95

Antworten:

259

Verwenden Sie~s zum Invertieren einer booleschen Reihe :

In [7]: s = pd.Series([True, True, False, True])

In [8]: ~s
Out[8]: 
0    False
1    False
2     True
3    False
dtype: bool

Verwenden von Python2.7, NumPy 1.8.0, Pandas 0.13.1:

In [119]: s = pd.Series([True, True, False, True]*10000)

In [10]:  %timeit np.invert(s)
10000 loops, best of 3: 91.8 µs per loop

In [11]: %timeit ~s
10000 loops, best of 3: 73.5 µs per loop

In [12]: %timeit (-s)
10000 loops, best of 3: 73.5 µs per loop

Ab Pandas 0.13.0 sind Serien keine Unterklassen mehr von numpy.ndarray; Sie sind jetzt Unterklassen von pd.NDFrame. Dies könnte etwas damit zu tun haben, warum np.invert(s)es nicht mehr so ​​schnell ist wie ~soder -s.

Vorsichtsmaßnahme: Die timeitErgebnisse können abhängig von vielen Faktoren variieren, einschließlich Hardware-, Compiler-, Betriebssystem-, Python-, NumPy- und Pandas-Versionen.

unutbu
quelle
Zur Kenntnis genommen. Was ist der Unterschied zwischen der Tilde und -?
Blz
Wierd, ich habe das tatsächlich getestet, tildewie es in der Dokumentation erwähnt wurde, aber es hat nicht die gleiche Leistung erbracht wie np.invert: S
root
@blz: Mindestens auf meinem Ubuntu - Rechner, läuft NumPy 1.6.2, die Leistung np.invert(s), ~sund -ssind alle gleich.
Unutbu
@root: Ich bin mir nicht sicher, warum unsere zeitlichen Ergebnisse so unterschiedlich sind, aber es kann durchaus passieren. Welches Betriebssystem und welche Version von NumPy verwenden Sie?
Unutbu
Auch unter Ubuntu, aber mit NumPy 1.7.0 ... ( np.bitwise_not(s)funktioniert genauso wie np.inverse).
Wurzel
32

Die Antwort von @ unutbu ist genau richtig. Ich wollte nur eine Warnung hinzufügen, dass Ihre Maske vom Typ bool sein muss, nicht 'Objekt'. Dh deine Maske kann noch nie eine Nans gehabt haben . Sehen Sie hier - auch wenn Ihre Maske jetzt nanofrei ist, bleibt sie vom Typ "Objekt".

Die Umkehrung einer 'Objekt'-Reihe löst keinen Fehler aus. Stattdessen erhalten Sie eine Müllmaske mit Ints, die nicht wie erwartet funktioniert.

In[1]: df = pd.DataFrame({'A':[True, False, np.nan], 'B':[True, False, True]})
In[2]: df.dropna(inplace=True)
In[3]: df['A']
Out[3]:
0    True
1   False
Name: A, dtype object
In[4]: ~df['A']
Out[4]:
0   -2
0   -1
Name: A, dtype object

Nachdem ich mit Kollegen darüber gesprochen habe, habe ich eine Erklärung: Es sieht so aus, als würden Pandas zum bitweisen Operator zurückkehren:

In [1]: ~True
Out[1]: -2

Wie @geher sagt, können Sie es mit Astype in Bool konvertieren, bevor Sie mit ~ invertieren

~df['A'].astype(bool)
0    False
1     True
Name: A, dtype: bool
(~df['A']).astype(bool)
0    True
1    True
Name: A, dtype: bool
JSharm
quelle
in Ihrem Beispiel kann die Ausgabe Ints Maske auf die Bool Serie Sie wollen mit umgewandelt werden .astype(bool)zB~df['A'].astype(bool)
Geher
Dies funktioniert, weil astype(bool)es vor dem ~ ~df['A'].astype(bool)vs(~df['A']).astype(bool)
JSharm
16

Ich probiere es einfach aus:

In [9]: s = Series([True, True, True, False])

In [10]: s
Out[10]: 
0     True
1     True
2     True
3    False

In [11]: -s
Out[11]: 
0    False
1    False
2    False
3     True
herrfz
quelle
Ich habe buchstäblich jeden anderen Operator als ausprobiert -! Ich werde dies für das nächste Mal berücksichtigen.
Blz
6

Sie können auch verwenden numpy.invert:

In [1]: import numpy as np

In [2]: import pandas as pd

In [3]: s = pd.Series([True, True, False, True])

In [4]: np.invert(s)
Out[4]: 
0    False
1    False
2     True
3    False

BEARBEITEN: Der Leistungsunterschied tritt unter Ubuntu 12.04, Python 2.7, NumPy 1.7.0 auf - scheint jedoch mit NumPy 1.6.2 nicht zu existieren:

In [5]: %timeit (-s)
10000 loops, best of 3: 26.8 us per loop

In [6]: %timeit np.invert(s)
100000 loops, best of 3: 7.85 us per loop

In [7]: %timeit ~s
10000 loops, best of 3: 27.3 us per loop
Wurzel
quelle
Auf einer anderen Plattform ist dies möglicherweise nicht korrekt. Win 7, Python 3.6.3 numpy 1.13.3, Pandas 0.20.3, (-s) sind die schnellsten, (~ s) die zweiten und np.invert (s) die langsamsten
gaozhidf
0

NumPy ist langsamer, weil es die Eingabe in boolesche Werte umwandelt (also werden None und 0 zu False und alles andere zu True).

import pandas as pd
import numpy as np
s = pd.Series([True, None, False, True])
np.logical_not(s)

gibt Ihnen

0    False
1     True
2     True
3    False
dtype: object

wohingegen ~ s abstürzen würde. In den meisten Fällen wäre Tilde eine sicherere Wahl als NumPy.

Pandas 0,25, NumPy 1,17

grofte
quelle