панди: кілька умов при індексації кадру даних - несподівана поведінка


135

Я фільтрую рядки у кадрі даних за значеннями у двох стовпцях.

Чомусь оператор АБО поводиться так, як я очікував, що оператор AND поводитиметься і навпаки.

Мій тестовий код:

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.


1
df.queryі, pd.evalздається, добре підходить для цього випадку використання. Для отримання інформації про pd.eval()сімейство функцій, їх особливості та випадки використання, будь ласка, відвідайте Динамічну оцінку вираження в пандах за допомогою pd.eval () .
cs95

Відповіді:


211

Як бачите, оператор AND скидає кожен рядок, у якому принаймні одне значення дорівнює -1. З іншого боку, оператор АБО вимагає, щоб обидва значення були рівними -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.


24
DataFrame.query()добре працює і тут. df.query('a != -1 or b != -1').
Філліп Хмара

5
Було знати, чому панди хочуть &і |знову, andі знову or?
печі

3
@stoves: у звичайному коді Python andі orє основна семантика Python, яку неможливо змінити. &і |, з іншого боку, мають відповідні спеціальні методи, які контролюють їх поведінку. (У рядках запиту, звичайно, ми можемо застосувати будь-який аналіз, який нам подобається.)
DSM

що цікаво, здається, що df[True & False]не вдається, але df[(True) & (False)]вдається (не перевірено на цьому прикладі)
3pitt

Чи можна було б розбити такий синтаксис на кілька рядків? Що було б найбільше PEP8?
tommy.carstensen

41

Ви можете використовувати query () , тобто:

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

У мене є ситуація, коли я думаю, що цей синтаксис має більше сенсу, наприклад: df.query ('' (a == 4 & b! = 2) | c == 3 ")
Aus_10,

9

Трохи теорії математичної логіки тут:

"НЕ і НЕ" - це те саме, що "НЕ (АБО б)" , так що:

"a NOT -1 AND 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)]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.