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.