Pandas: несколько условий при индексировании кадра данных - неожиданное поведение
Я фильтрую строки в фрейме данных значениями в двух столбцах.
По какой-то причине оператор OR ведет себя так, как я ожидал бы, что оператор AND будет вести себя и наоборот.
Мой тестовый код:
import pandas as pd
df = pd.DataFrame({'a': range(5), 'b': range(5) })
# let 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 (|)',])
И результат:
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]
Как вы можете видеть, оператор AND
опускает каждую строку, в которой хотя бы одно значение равно -1
. С другой стороны, оператор OR
требует, чтобы оба значения были равны -1
, чтобы опустить их. Я бы ожидал точно противоположного результата. Может ли кто-нибудь объяснить это поведение, пожалуйста?
Я использую pandas 0.13.1.
Ответы
Ответ 1
Как вы можете видеть, оператор И оставляет каждую строку, в которой, по крайней мере, один значение равно -1. С другой стороны, оператор OR требует значения равны -1, чтобы удалить их.
Это правильно. Помните, что вы пишете условие с точки зрения того, что вы хотите сохранить, а не с точки зрения того, что вы хотите сбросить. Для df1
:
df1 = df[(df.a != -1) & (df.b != -1)]
Вы говорите: "Сохраняйте строки, в которых df.a
не является -1, а df.b
не равно -1", что равнозначно удалению каждой строки, в которой по крайней мере одно значение равно -1.
Для df2
:
df2 = df[(df.a != -1) | (df.b != -1)]
Вы говорите: "Сохраняйте строки, в которых либо df.a
, либо df.b
не равно -1", что совпадает с удалением строк, где оба значения равны -1.
PS: скованный доступ, такой как df['a'][1] = -1
, может вызвать у вас проблемы. Лучше привыкнуть использовать .loc
и .iloc
.
Ответ 2
Вы можете использовать query(), то есть:
df_filtered = df.query('a == 4 & b != 2')
Ответ 3
Немного математической теории логики здесь:
"НЕ А И НЕ Б" - это то же самое, что "НЕ (ИЛИ Б)", поэтому:
"a NOT -1 И b NOT -1" эквивалентно "NOT (a - -1 ИЛИ b - -1)", что противоположно (дополнение) к "(a - -1 ИЛИ b -" -1)".
Поэтому, если вы хотите получить противоположный результат, df1 и df2 должны быть такими, как показано ниже:
df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a == -1) | (df.b == -1)]