Come posso ottenere il logico NON logico degli elementi di una serie di panda?


229

Ho un Seriesoggetto Panda contenente valori booleani. Come posso ottenere una serie contenente la logica NOTdi ciascun valore?

Ad esempio, considera una serie contenente:

True
True
True
False

La serie che vorrei ottenere conterrebbe:

False
False
False
True

Sembra che dovrebbe essere ragionevolmente semplice, ma a quanto pare ho smarrito il mio mojo = (


1
È importante che i dati non contengano objecttipi per il funzionamento delle risposte seguenti, quindi utilizzare:~ df.astype('bool')
LearnOPhile

Ho scritto di tutti gli operatori logici in questo post . Il post include anche alternative.
1919

Risposte:


260

Per invertire una serie booleana, utilizzare~s :

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

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

Usando Python2.7, NumPy 1.8.0, Panda 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

A partire da Panda 0.13.0, le serie non sono più sottoclassi di numpy.ndarray; ora sono sottoclassi di pd.NDFrame. Questo potrebbe avere a che fare con il perché np.invert(s)non è più veloce di ~so -s.

Avvertenza: i timeitrisultati possono variare in base a molti fattori tra cui versioni hardware, compilatore, SO, Python, NumPy e Pandas.


Debitamente annotato. Oltre ad essere molto più lento, qual è la differenza tra la tilde e -?
blz

Stranamente, l'ho testato tildecome è stato menzionato nella documentazione, ma non ha funzionato come np.invert: S
root

@blz: Almeno sulla mia macchina Ubuntu, in esecuzione NumPy 1.6.2, le prestazioni di np.invert(s), ~se -ssono tutti uguali.
unutbu,

@root: Non sono sicuro del motivo per cui c'è una così grande discrepanza nei nostri risultati temporali, ma certamente può succedere. Quale sistema operativo e versione di NumPy stai usando?
unutbu,

Anche su Ubuntu, ma usando NumPy 1.7.0 ... ( np.bitwise_not(s)funziona come np.inverse).
radice

32

La risposta di @ unutbu è perfetta, volevo solo aggiungere un avvertimento che la tua maschera deve essere dtype bool, non "oggetto". Cioè la tua maschera non può aver mai avuto nan. Vedi qui - anche se ora la tua maschera è priva di nan, rimarrà di tipo "oggetto".

L'inverso di una serie di "oggetti" non genererà un errore, invece otterrai una maschera di immondizia che non funzionerà come previsto.

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

Dopo aver parlato con i colleghi di questo, ho una spiegazione: sembra che i panda stiano tornando all'operatore bit a bit:

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

Come dice @geher, puoi convertirlo in bool con astype prima di invertire con ~

~df['A'].astype(bool)
0    False
1     True
Name: A, dtype: bool
(~df['A']).astype(bool)
0    True
1    True
Name: A, dtype: bool

nel tuo esempio, la maschera di output ints può essere convertita nella serie bool desiderata con .astype(bool)es.~df['A'].astype(bool)
geher

Questo funziona perché astype(bool)sta accadendo prima del ~ ~df['A'].astype(bool)vs(~df['A']).astype(bool)
JSharm il

16

Ci provo e basta:

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

Ho letteralmente provato tutti gli operatori tranne -! Lo terrò a mente per la prossima volta.
blz

6

Puoi anche usare 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

EDIT: La differenza nelle prestazioni appare su Ubuntu 12.04, Python 2.7, NumPy 1.7.0 - non sembra esistere usando NumPy 1.6.2 anche se:

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

potrebbe non essere corretto su una piattaforma diversa. Win 7, python 3.6.3 numpy 1.13.3, panda 0.20.3, (-s) sarà il più veloce, (~ s) è il secondo e np.invert (s) è il più lento
gaozhidf

0

NumPy è più lento perché invia l'input a valori booleani (quindi None e 0 diventa False e tutto il resto diventa True).

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

ti dà

0    False
1     True
2     True
3    False
dtype: object

mentre ~ s andrebbe in crash. Nella maggior parte dei casi, tilde sarebbe una scelta più sicura di NumPy.

Panda 0,25, NumPy 1,17

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.