gấu trúc: nhiều điều kiện trong khi lập chỉ mục khung dữ liệu - hành vi không mong muốn


135

Tôi đang lọc các hàng trong khung dữ liệu theo các giá trị trong hai cột.

Vì một số lý do mà toán tử OR hoạt động như tôi mong đợi toán tử AND sẽ hoạt động và ngược lại.

Mã thử nghiệm của tôi:

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 (|)',])

Và kết quả:

      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]

Như bạn có thể thấy, ANDtoán tử giảm mỗi hàng có ít nhất một giá trị bằng -1. Mặt khác, ORtoán tử yêu cầu cả hai giá trị bằng nhau -1để loại bỏ chúng. Tôi sẽ mong đợi chính xác kết quả ngược lại. Bất cứ ai có thể giải thích hành vi này, xin vui lòng?

Tôi đang sử dụng gấu trúc 0.13.1.


1
df.querypd.evalcó vẻ như phù hợp với trường hợp sử dụng này. Để biết thông tin về nhóm pd.eval()hàm, tính năng và trường hợp sử dụng của chúng, vui lòng truy cập Đánh giá biểu thức động ở gấu trúc bằng pd.eval () .
cs95

Câu trả lời:


211

Như bạn có thể thấy, toán tử AND giảm mọi hàng có ít nhất một giá trị bằng -1. Mặt khác, toán tử OR yêu cầu cả hai giá trị phải bằng -1 để loại bỏ chúng.

Đúng rồi. Hãy nhớ rằng bạn đang viết điều kiện về những gì bạn muốn giữ lại , không phải về những gì bạn muốn bỏ đi. Đối với df1:

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

Bạn đang nói "giữ nguyên các hàng df.akhông phải -1 và df.bkhông phải -1", điều này cũng giống như giảm mọi hàng có ít nhất một giá trị là -1.

Đối với df2:

df2 = df[(df.a != -1) | (df.b != -1)]

Bạn đang nói "giữ nguyên các hàng có df.ahoặc df.bkhông phải là -1", điều này cũng giống như giảm các hàng có cả hai giá trị là -1.

Tái bút: truy cập chuỗi như df['a'][1] = -1có thể khiến bạn gặp rắc rối. Tốt hơn hết là bạn nên có thói quen sử dụng .loc.iloc.


24
DataFrame.query()hoạt động tốt ở đây quá. df.query('a != -1 or b != -1').
Phillip Cloud

5
Xảy ra để biết tại sao gấu trúc muốn &|hơn nữa andor?
bếp từ

3
@stoves: bằng mã Python bình thường andorcó ngữ nghĩa Python cơ bản không thể sửa đổi. &|, mặt khác, có các phương pháp đặc biệt tương ứng để kiểm soát hành vi của họ. (Tất nhiên, trong các chuỗi truy vấn, chúng tôi có thể tự do áp dụng bất kỳ phân tích cú pháp nào mà chúng tôi muốn.)
DSM

thú vị là, nó có vẻ như df[True & False]thất bại nhưng df[(True) & (False)]thành công (không được thử nghiệm trên ví dụ này)
3pitt

Có thể ngắt loại cú pháp này trên nhiều dòng không? PEP8 sẽ là gì nhất?
tommy.carstensen

41

Bạn có thể sử dụng query () , tức là:

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

Tôi có một tình huống mà tôi nghĩ rằng cú pháp này có ý nghĩa hơn, ví dụ: df.query ('' (a == 4 & b! = 2) | c == 3 ")
Aus_10

9

Một chút lý thuyết logic toán học ở đây:

"NOT a AND NOT b" giống với "NOT (a OR b)" , do đó:

"a NOT -1 AND b NOT -1" tương đương với "NOT (a là -1 HOẶC b là -1)" , ngược lại (Phần bổ sung) của "(a là -1 HOẶC b là -1)" .

Vì vậy, nếu bạn muốn kết quả hoàn toàn ngược lại, df1 và df2 phải như sau:

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a == -1) | (df.b == -1)]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.