¿Cómo puedo obtener el NOT lógico por elementos de una serie de pandas?
Tengo un Series
objeto pandas que contiene valores booleanos. ¿ Cómo puedo obtener una serie que contenga la lógica NOT
de cada valor?
Por ejemplo, considere una serie que contenga:
True
True
True
False
La serie que me gustaría conseguir contendría:
False
False
False
True
Esto parece que debería ser razonablemente simple, pero aparentemente he perdido mi encanto =(
Para invertir una serie booleana, utilice~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é ya np.invert(s)
no es tan rápido como ~s
o -s
.
Advertencia: timeit
los resultados pueden variar dependiendo de muchos factores, incluido el hardware, el compilador, el sistema operativo, las versiones de Python, NumPy y Pandas.
La respuesta de @unutbu es acertada, solo quería agregar una advertencia de que su máscara debe ser dtype bool, no 'objeto'. Es decir, tu máscara nunca pudo haber tenido la de ninguna abuela. Vea aquí : incluso si su máscara ahora no contiene nan, seguirá siendo del tipo "objeto".
La inversa de una serie de 'objetos' no arrojará un error; en su lugar, obtendrá una máscara de basura de enteros que no funcionará como esperaba.
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 que pandas está volviendo al operador bit a bit:
In [1]: ~True
Out[1]: -2
Como dice @geher, puedes convertirlo a bool con astype antes de invertir 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
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