pandas: conditions multiples lors de l'indexation de la trame de données - comportement inattendu


135

Je filtre les lignes d'un dataframe par valeurs dans deux colonnes.

Pour une raison quelconque, l'opérateur OR se comporte comme je m'attendrais à ce que l'opérateur AND se comporte et vice versa.

Mon code de test:

import pandas as pd

df = pd.DataFrame({'a': range(5), 'b': range(5) })

# let's insert some -1 values
df['a'][1] = -1
df['b'][1] = -1
df['a'][3] = -1
df['b'][4] = -1

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a != -1) | (df.b != -1)]

print pd.concat([df, df1, df2], axis=1,
                keys = [ 'original df', 'using AND (&)', 'using OR (|)',])

Et le résultat:

      original df      using AND (&)      using OR (|)    
             a  b              a   b             a   b
0            0  0              0   0             0   0
1           -1 -1            NaN NaN           NaN NaN
2            2  2              2   2             2   2
3           -1  3            NaN NaN            -1   3
4            4 -1            NaN NaN             4  -1

[5 rows x 6 columns]

Comme vous pouvez le voir, l' ANDopérateur supprime chaque ligne dans laquelle au moins une valeur est égale -1. D'autre part, l' ORopérateur exige que les deux valeurs soient égales à -1pour les supprimer. Je m'attendrais exactement au résultat opposé. Quelqu'un pourrait-il expliquer ce comportement, s'il vous plaît?

J'utilise pandas 0.13.1.


1
df.queryet pd.evalsemblent bien adaptés à ce cas d'utilisation. Pour plus d'informations sur la pd.eval()famille de fonctions, leurs caractéristiques et leurs cas d'utilisation, veuillez visiter Évaluation des expressions dynamiques dans les pandas à l'aide de pd.eval () .
— cs95

Réponses:


211

Comme vous pouvez le voir, l'opérateur AND supprime chaque ligne dans laquelle au moins une valeur est égale à -1. D'autre part, l'opérateur OR exige que les deux valeurs soient égales à -1 pour les supprimer.

C'est vrai. N'oubliez pas que vous écrivez la condition en termes de ce que vous voulez conserver , pas en termes de ce que vous voulez laisser tomber. Pour df1:

df1 = df[(df.a != -1) & (df.b != -1)]

Vous dites "conserver les lignes dans lesquelles df.an'est pas -1 et df.bn'est pas -1", ce qui revient à supprimer toutes les lignes dans lesquelles au moins une valeur est -1.

Pour df2:

df2 = df[(df.a != -1) | (df.b != -1)]

Vous dites "conserver les lignes dans lesquelles soit df.aou df.bnon -1", ce qui revient à supprimer des lignes où les deux valeurs sont -1.

PS: un accès enchaîné df['a'][1] = -1peut vous causer des ennuis. Il vaut mieux prendre l'habitude d'utiliser .locet .iloc.


24
DataFrame.query()fonctionne bien ici aussi. df.query('a != -1 or b != -1').
— Phillip Cloud

5
Arriver à savoir pourquoi les pandas veulent &et |encore andet or?
— poêles

3
@stoves: en code Python normal, andet oront une sémantique Python de base qui ne peut pas être modifiée &et |, d'autre part, ont des méthodes spéciales correspondantes qui contrôlent leur comportement. (Dans les chaînes de requête, bien sûr, nous sommes libres d'appliquer l'analyse de notre choix.)
— DSM

intéressant, cela semble df[True & False]échouer mais df[(True) & (False)]réussit (non testé sur cet exemple)
— 3pitt

Serait-il possible de briser ce type de syntaxe sur plusieurs lignes? Quel serait le plus PEP8?
— tommy.carstensen

41

Vous pouvez utiliser query () , c'est-à-dire:

df_filtered = df.query('a == 4 & b != 2')

J'ai une situation où je pense que cette syntaxe a plus de sens, par exemple: df.query ('' (a == 4 & b! = 2) | c == 3 ")
— Aus_10

9

Un peu de théorie de la logique mathématique ici:

"NOT a AND NOT b" équivaut à "NOT (a OR b)" , donc:

"a NOT -1 AND b NOT -1" est équivalent à "NOT (a is -1 OR b is -1)" , qui est l'opposé (Complement) de "(a is -1 OR b is -1)" .

Donc, si vous voulez un résultat exactement opposé, df1 et df2 devraient être comme ci-dessous:

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a == -1) | (df.b == -1)]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.