¿Cómo puedo obtener el elemento lógico NO de una Serie de pandas?


Tengo un objeto pandas Series que contiene valores booleanos. ¿Cómo puedo obtener una serie que contiene el NOT lógico de cada valor?

Por ejemplo, considere una serie que contenga:

True
True
True
False

La serie que me gustaría obtener contendría:

False
False
False
True

Esto parece que debería ser razonablemente simple, pero aparentemente he perdido mi mojo =(

Author: Steven C. Howell, 2013-04-14

4 answers

Para invertir una serie booleana, use ~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, 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

A partir de Pandas 0.13.0, las Series ya no son subclases de numpy.ndarray; ahora son subclases de pd.NDFrame. Esto podría tener algo que ver con por qué np.invert(s) ya no es tan rápido como ~s o -s.

Advertencia: timeit los resultados pueden variar dependiendo de muchos factores, incluidas las versiones de hardware, compilador, sistema operativo, Python, NumPy y Pandas.

 153
Author: unutbu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-28 18:58:59

Solo le doy una oportunidad:

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
 11
Author: herrfz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-14 10:53:08

La respuesta de@unutbu es acertada, solo quería agregar una advertencia de que su máscara debe ser dtype bool, no 'object'. Es decir, su máscara no puede tener nunca tuvo ninguna nan. Vea aquí - incluso si su máscara está libre de nan ahora, seguirá siendo de tipo 'objeto'.

El inverso de una serie 'object' no arrojará un error, en su lugar obtendrá una máscara de basura de ints que no funcionará como espera.

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

Después de hablar con colegas sobre esto tengo una explicación: Parece como pandas está volviendo al operador bitwise:

In [1]: ~True
Out[1]: -2
 9
Author: JSharm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-08 17:29:20

También Se puede utilizar 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

EDITAR: La diferencia en el rendimiento aparece en Ubuntu 12.04, Python 2.7, NumPy 1.7.0-no parece existir usando NumPy 1.6.2 aunque:

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
 5
Author: root,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-14 15:34:19