J'ai un objet pandas Series
contenant des valeurs booléennes. Comment puis-je obtenir une série contenant le NOT
logique de chaque valeur?
Par exemple, considérons une série contenant:
True
True
True
False
La série que j'aimerais avoir contiendrait:
False
False
False
True
Cela semble être assez simple, mais apparemment, j’ai égaré mon mojo = (
Pour inverser une série booléenne, tilisez ~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
Avec 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
À partir de Pandas 0.13.0, les séries ne sont plus des sous-classes de numpy.ndarray
; ils sont maintenant des sous-classes de pd.NDFrame
. Cela pourrait avoir quelque chose à voir avec pourquoi np.invert(s)
n'est plus aussi rapide que ~s
ou -s
.
Mise en garde: timeit
les résultats peuvent varier en fonction de nombreux facteurs, notamment le matériel, le compilateur, le système d'exploitation, Python, NumPy et Pandas versions.
La réponse de @ unutbu est parfaite, je voulais juste ajouter un avertissement indiquant que votre masque doit être dactylographié, pas d'objet. C'est-à-dire que votre masque ne peut avoir jamais jamais eu de nan. Voir ici - même si votre masque est maintenant sans nan, il restera du type 'objet'.
L'inverse d'une série 'object' ne générera pas d'erreur, mais vous obtiendrez un masque de déchets contenant des données inertes qui ne fonctionneront pas comme prévu.
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
Après en avoir parlé à des collègues à propos de celui-ci, j'ai une explication: il semble que pandas revienne à l'opérateur binaire:
In [1]: ~True
Out[1]: -2
Je viens de tenter le coup:
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
Vous pouvez également utiliser 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 différence de performance apparaît sur Ubuntu 12.04, Python 2.7, NumPy 1.7.0 - ne semble pas exister avec NumPy 1.6.2 bien que:
_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
_