web-dev-qa-db-fra.com

Opérateurs logiques pour l'indexation booléenne dans les pandas

Je travaille avec un index booléen dans les pandas ..___ La question est pourquoi la déclaration:

a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]

fonctionne bien alors que

a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]

existe avec erreur?

Exemple:

a=pd.DataFrame({'x':[1,1],'y':[10,20]})

In: a[(a['x']==1)&(a['y']==10)]
Out:    x   y
     0  1  10

In: a[(a['x']==1) and (a['y']==10)]
Out: ValueError: The truth value of an array with more than one element is ambiguous.     Use a.any() or a.all()
74
user2988577

Quand tu dis

(a['x']==1) and (a['y']==10)

Vous demandez implicitement à Python de convertir (a['x']==1) et (a['y']==10) en valeurs booléennes. 

Les tableaux NumPy (de longueur supérieure à 1) et les objets Pandas tels que Series n'ont pas de valeur booléenne - en d'autres termes, ils soulèvent 

ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().

lorsqu'il est utilisé comme valeur booléenne. C'est parce que son pas clair quand il devrait être vrai ou faux . Certains utilisateurs peuvent supposer qu'ils sont vrais s'ils ont une longueur non nulle, comme une liste Python. D'autres pourraient désirer que ce ne soit vrai que si tous ses éléments sont vrais. D'autres voudront peut-être qu'il soit vrai si aucun de ses éléments sont vrais. 

Comme il y a tellement d'attentes contradictoires, les concepteurs de NumPy et de Pandas refusent de deviner et élèvent plutôt une ValueError.

Au lieu de cela, vous devez être explicite en appelant la méthode empty(), all() ou any() pour indiquer le comportement souhaité.

Dans ce cas, cependant, il semblerait que vous ne souhaitiez pas d'évaluation booléenne, mais plutôt élément-sage logical-and. C’est ce que l’opérateur binaire & exécute:

(a['x']==1) & (a['y']==10)

retourne un tableau booléen. 


En passant, comme alexpmil note , , Les parenthèses sont obligatoires car & a une priorité supérieure à l'opérateur à ==. Sans les parenthèses, a['x']==1 & a['y']==10 serait évalué comme étant a['x'] == (1 & a['y']) == 10, ce qui entraînerait être équivalent à la comparaison chaînée (a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10). C’est une expression de la forme Series and Series. L’utilisation de and avec deux séries déclencherait à nouveau la même ValueError comme ci-dessus. C'est pourquoi les parenthèses sont obligatoires.

131
unutbu

Opérateurs logiques pour l'indexation booléenne dans les pandas

Il est important de réaliser que vous ne pouvez utiliser aucun des opérateurs logiques Python (and, or ou not) sur pandas.Series ou pandas.DataFrames (de même, vous ne pouvez pas les utiliser sur numpy.arrays avec plusieurs éléments). La raison pour laquelle vous ne pouvez pas les utiliser est parce qu'ils appellent implicitement bool sur leurs opérandes, ce qui génère une exception, car ces structures de données ont décidé que le booléen d'un tableau est ambigu:

>>> import numpy as np
>>> import pandas as pd
>>> arr = np.array([1,2,3])
>>> s = pd.Series([1,2,3])
>>> df = pd.DataFrame([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> bool(df)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

J'ai couvert cette question de manière plus détaillée dans ma réponse à la "valeur de vérité d'une série est ambiguë. Utilisez a.empty, a.bool (), a.item (), a.any () ou a.all ( ) "Q + A .

Fonctions logiques NumPys

Toutefois, NumPy fournit des équivalents opérationnels élément par élément à ces opérateurs sous forme de fonctions utilisables dans numpy.array, pandas.Series, pandas.DataFrame ou toute autre sous-classe numpy.array (conforme):

Donc, essentiellement, on devrait utiliser (en supposant que df1 et df2 sont des pandas DataFrames):

np.logical_and(df1, df2)
np.logical_or(df1, df2)
np.logical_not(df1)
np.logical_xor(df1, df2)

Fonctions binaires et opérateurs binaires pour les booléens

Cependant, si vous avez un tableau NumPy booléen, une série de pandas ou des cadres de données de pandas, vous pouvez également utiliser le fonctions au niveau des bits élémentaires (pour les booléens, ils sont - ou du moins devraient être - indiscernables des fonctions logiques):

Les opérateurs sont généralement utilisés. Toutefois, lorsque combiné avec des opérateurs de comparaison, il ne faut pas oublier de mettre la comparaison entre parenthèses, car les opérateurs au niveau du bit ont un priorité supérieure à celle des opérateurs de comparaison :

(df1 < 10) | (df2 > 10)  # instead of the wrong df1 < 10 | df2 > 10

Cela peut être irritant car les opérateurs logiques Python ont une préséance inférieure à celle des opérateurs de comparaison, vous écrivez donc normalement a < 10 and b > 10 (où a et b sont par exemple des entiers simples) et n'ont pas besoin de la parenthèse.

Différences entre les opérations logiques et binaires (sur les non-booléens)

Il est vraiment important de souligner que les opérations sur les bits et les opérations logiques ne sont équivalentes que pour les tableaux booléens NumPy (et boolean Series & DataFrames). Si ceux-ci ne contiennent pas de booléens, les opérations donneront des résultats différents. Je vais inclure des exemples utilisant des tableaux NumPy mais les résultats seront similaires pour les structures de données de pandas:

>>> import numpy as np
>>> a1 = np.array([0, 0, 1, 1])
>>> a2 = np.array([0, 1, 0, 1])

>>> np.logical_and(a1, a2)
array([False, False, False,  True])
>>> np.bitwise_and(a1, a2)
array([0, 0, 0, 1], dtype=int32)

Et comme NumPy (et de même les pandas) fait différentes choses pour les index booléens ( tableaux de valeur booléens ou «masqués» ) et entiers ( tableaux de indices ), les résultats de l'indexation seront également différents. :

>>> a3 = np.array([1, 2, 3, 4])

>>> a3[np.logical_and(a1, a2)]
array([4])
>>> a3[np.bitwise_and(a1, a2)]
array([1, 1, 1, 2])

Sommaire

Logical operator | NumPy logical function | NumPy bitwise function | Bitwise operator
-------------------------------------------------------------------------------------
       and       |  np.logical_and        | np.bitwise_and         |        &
-------------------------------------------------------------------------------------
       or        |  np.logical_or         | np.bitwise_or          |        |
-------------------------------------------------------------------------------------
                 |  np.logical_xor        | np.bitwise_xor         |        ^
-------------------------------------------------------------------------------------
       not       |  np.logical_not        | np.invert              |        ~

l'opérateur logique ne fonctionne pas pour les baies NumPy, les pandas Series et les pandas DataFrames. Les autres travaillent sur ces structures de données (et les objets Python simples) et au niveau des éléments . Cependant, soyez prudent avec l'inversion au niveau des bits sur Python ordinaire bools car le bool sera interprété comme un entier dans ce contexte (par exemple, ~False renvoie -1 et ~True renvoie -2).

0
MSeifert