панды: несколько условий при индексировании фрейма данных-неожиданное поведение
я фильтрую строки в фрейме данных по значениям в двух столбцах.
по какой-то причине оператор OR ведет себя так, как я ожидал бы, и оператор будет вести себя и наоборот.
мой тестовый код:
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 (|)',])
и в итоге:
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
отказаться от них. Я бы ожидайте прямо противоположного результата. Кто-нибудь может объяснить это поведение, пожалуйста?
Я использую панды 0.13.1.
2 ответа:
как вы можете видеть, оператор AND отбрасывает каждую строку, в которой хотя бы один значение равно -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
.
можно использовать query (), например:
df_filtered = df.query('a == 4 & b != 2')