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 = (


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.


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

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

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

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

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.