web-dev-qa-db-fra.com

pandas: conditions multiples lors de l'indexation du bloc de données - comportement inattendu

Je filtre les lignes dans un cadre de données par des valeurs sur deux colonnes.

Pour une raison quelconque, l'opérateur OR se comporte comme je l'attendrais de l'opérateur AND, et inversement.

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 constater, l'opérateur AND supprime chaque ligne dans laquelle au moins une valeur est égale à -1. D'autre part, l'opérateur OR requiert que les deux valeurs soient égales à -1 pour 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.

89
Wojciech Walczak

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

C'est vrai. Rappelez-vous que vous écrivez la condition en termes de ce que vous voulez garder, pas en termes de ce que vous voulez supprimer. Pour df1:

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

Vous dites "conserver les lignes dans lesquelles df.a n'est pas -1 et df.b n'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 df.a ou df.b n'est pas -1", ce qui revient au même que supprimer des lignes dans lesquelles les deux valeurs sont -1.

PS: un accès chaîné comme df['a'][1] = -1 peut vous causer des ennuis. Il est préférable de prendre l'habitude d'utiliser .loc et .iloc.

148
DSM

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

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

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

"NOT a AND NOT b" est identique à "NOT (a OR b ) ", donc:

"a NOT -1 ET b NOT -1" est équivalent à "NOT (a est -1 OR b est -1) ", qui est opposé (Complément) de " (a est -1 OR b est -1) ".

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

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