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.
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
.
Vous pouvez utiliser query () , c'est-à-dire:
df_filtered = df.query('a == 4 & b != 2')
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)]