TLDR; Toán tử logic trong Pandas là &
, |
và ~
, dấu ngoặc đơn (...)
là quan trọng!
Python là and
, or
và not
khai thác hợp lý được thiết kế để làm việc với vô hướng. Vì vậy, Pandas phải làm tốt hơn một lần nữa và ghi đè các toán tử bitwise để đạt được phiên bản véc tơ (yếu tố khôn ngoan) của chức năng này.
Vì vậy, sau đây trong python ( exp1
và exp2
là các biểu thức đánh giá kết quả boolean) ...
exp1 and exp2 # Logical AND
exp1 or exp2 # Logical OR
not exp1 # Logical NOT
... sẽ dịch sang ...
exp1 & exp2 # Element-wise logical AND
exp1 | exp2 # Element-wise logical OR
~exp1 # Element-wise logical NOT
cho gấu trúc.
Nếu trong quá trình thực hiện thao tác logic bạn nhận được a ValueError
, thì bạn cần sử dụng dấu ngoặc đơn để nhóm:
(exp1) op (exp2)
Ví dụ,
(df['col1'] == x) & (df['col2'] == y)
Và như thế.
Lập chỉ mục Boolean : Một hoạt động phổ biến là tính toán các mặt nạ boolean thông qua các điều kiện logic để lọc dữ liệu. Pandas cung cấp ba toán tử:&
cho logic AND,|
cho logic OR và~
cho logic KHÔNG.
Hãy xem xét các thiết lập sau:
np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (5, 3)), columns=list('ABC'))
df
A B C
0 5 0 3
1 3 7 9
2 3 5 2
3 4 7 6
4 8 8 1
Logic VÀ
Đối với df
ở trên, giả sử bạn muốn trả về tất cả các hàng trong đó A <5 và B> 5. Điều này được thực hiện bằng cách tính mặt nạ cho từng điều kiện riêng biệt và ANDing chúng.
&
Toán tử bitwise quá tải
Trước khi tiếp tục, vui lòng lưu ý đoạn trích cụ thể này của tài liệu, trạng thái
Một hoạt động phổ biến khác là sử dụng các vectơ boolean để lọc dữ liệu. Các toán tử là: |
for or
, &
for and
và ~
for not
. Chúng phải được nhóm lại bằng cách sử dụng dấu ngoặc đơn , vì theo mặc định Python sẽ đánh giá một biểu thức df.A > 2 & df.B < 3
như df.A > (2 &
df.B) < 3
, trong khi thứ tự đánh giá mong muốn là (df.A > 2) & (df.B <
3)
.
Vì vậy, với ý nghĩ này, phần tử logic logic VÀ có thể được thực hiện với toán tử bitwise &
:
df['A'] < 5
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'] > 5
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
(df['A'] < 5) & (df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Và bước lọc tiếp theo chỉ đơn giản là,
df[(df['A'] < 5) & (df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Các dấu ngoặc đơn được sử dụng để ghi đè thứ tự ưu tiên mặc định của các toán tử bitwise, có độ ưu tiên cao hơn các toán tử có điều kiện <
và >
. Xem phần Ưu tiên của Người vận hành trong tài liệu python.
Nếu bạn không sử dụng dấu ngoặc đơn, biểu thức được đánh giá không chính xác. Ví dụ: nếu bạn vô tình thử thứ gì đó như
df['A'] < 5 & df['B'] > 5
Nó được phân tích thành
df['A'] < (5 & df['B']) > 5
Trở thành,
df['A'] < something_you_dont_want > 5
Mà trở thành (xem tài liệu python về so sánh toán tử chuỗi ),
(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)
Trở thành,
# Both operands are Series...
something_else_you_dont_want1 and something_else_you_dont_want2
Mà ném
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Vì vậy, đừng phạm sai lầm! 1
Tránh dấu ngoặc đơn Nhóm cách
khắc phục thực sự khá đơn giản. Hầu hết các toán tử có một phương thức ràng buộc tương ứng cho DataFrames. Nếu các mặt nạ riêng lẻ được xây dựng bằng cách sử dụng các hàm thay vì các toán tử có điều kiện, bạn sẽ không còn cần phải nhóm theo parens để chỉ định thứ tự đánh giá:
df['A'].lt(5)
0 True
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'].gt(5)
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
df['A'].lt(5) & df['B'].gt(5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
Xem phần về So sánh linh hoạt. . Tóm lại, chúng ta có
╒════╤════════════╤════════════╕
│ │ Operator │ Function │
╞════╪════════════╪════════════╡
│ 0 │ > │ gt │
├────┼────────────┼────────────┤
│ 1 │ >= │ ge │
├────┼────────────┼────────────┤
│ 2 │ < │ lt │
├────┼────────────┼────────────┤
│ 3 │ <= │ le │
├────┼────────────┼────────────┤
│ 4 │ == │ eq │
├────┼────────────┼────────────┤
│ 5 │ != │ ne │
╘════╧════════════╧════════════╛
Một tùy chọn khác để tránh dấu ngoặc đơn là sử dụng DataFrame.query
(hoặc eval
):
df.query('A < 5 and B > 5')
A B C
1 3 7 9
3 4 7 6
Tôi đã ghi chép rộng rãiquery
và eval
trong Đánh giá biểu hiện động trong gấu trúc bằng cách sử dụng pd.eval () .
operator.and_
Cho phép bạn thực hiện thao tác này một cách có chức năng. Các cuộc gọi nội bộ Series.__and__
tương ứng với toán tử bitwise.
import operator
operator.and_(df['A'] < 5, df['B'] > 5)
# Same as,
# (df['A'] < 5).__and__(df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
df[operator.and_(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Bạn sẽ không cần điều này, nhưng nó rất hữu ích để biết.
Tổng quát hóa: np.logical_and
(và logical_and.reduce
)
Một cách khác là sử dụng np.logical_and
, cũng không cần nhóm dấu ngoặc đơn:
np.logical_and(df['A'] < 5, df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
Name: A, dtype: bool
df[np.logical_and(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
np.logical_and
là một ufunc (Hàm đa năng) và hầu hết các ufunc đều có một reduce
phương thức. Điều này có nghĩa là việc khái quát hóa sẽ dễ dàng hơn logical_and
nếu bạn có nhiều mặt nạ để AND. Ví dụ, để VÀ mặt nạ m1
và m2
và m3
với &
, bạn sẽ phải làm
m1 & m2 & m3
Tuy nhiên, một lựa chọn dễ dàng hơn là
np.logical_and.reduce([m1, m2, m3])
Điều này rất mạnh mẽ, bởi vì nó cho phép bạn xây dựng trên đầu trang này với logic phức tạp hơn (ví dụ: tạo mặt nạ động trong phần hiểu danh sách và thêm tất cả chúng):
import operator
cols = ['A', 'B']
ops = [np.less, np.greater]
values = [5, 5]
m = np.logical_and.reduce([op(df[c], v) for op, c, v in zip(ops, cols, values)])
m
# array([False, True, False, True, False])
df[m]
A B C
1 3 7 9
3 4 7 6
1 - Tôi biết tôi đang làm phiền về điểm này, nhưng xin hãy đồng ý với tôi. Đây là một sai lầm rất , rất phổ biến của người mới bắt đầu, và phải được giải thích rất kỹ lưỡng.
Hợp lý HOẶC
Đối với phần df
trên, giả sử bạn muốn trả về tất cả các hàng trong đó A == 3 hoặc B == 7.
Quá tải bitwise |
df['A'] == 3
0 False
1 True
2 True
3 False
4 False
Name: A, dtype: bool
df['B'] == 7
0 False
1 True
2 False
3 True
4 False
Name: B, dtype: bool
(df['A'] == 3) | (df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[(df['A'] == 3) | (df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Nếu bạn chưa có, xin vui lòng đọc phần trên Logic VÀ ở trên, tất cả các cảnh báo áp dụng ở đây.
Ngoài ra, hoạt động này có thể được chỉ định với
df[df['A'].eq(3) | df['B'].eq(7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
operator.or_
Các cuộc gọi Series.__or__
dưới mui xe.
operator.or_(df['A'] == 3, df['B'] == 7)
# Same as,
# (df['A'] == 3).__or__(df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[operator.or_(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
np.logical_or
Đối với hai điều kiện, sử dụng logical_or
:
np.logical_or(df['A'] == 3, df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df[np.logical_or(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Đối với nhiều mặt nạ, sử dụng logical_or.reduce
:
np.logical_or.reduce([df['A'] == 3, df['B'] == 7])
# array([False, True, True, True, False])
df[np.logical_or.reduce([df['A'] == 3, df['B'] == 7])]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
Logic KHÔNG
Đưa ra một mặt nạ, chẳng hạn như
mask = pd.Series([True, True, False])
Nếu bạn cần đảo ngược mọi giá trị boolean (để kết quả cuối cùng là [False, False, True]
), thì bạn có thể sử dụng bất kỳ phương thức nào dưới đây.
Bitwise ~
~mask
0 False
1 False
2 True
dtype: bool
Một lần nữa, các biểu thức cần phải được ngoặc.
~(df['A'] == 3)
0 True
1 False
2 False
3 True
4 True
Name: A, dtype: bool
Điều này gọi nội bộ
mask.__invert__()
0 False
1 False
2 True
dtype: bool
Nhưng đừng sử dụng nó trực tiếp.
operator.inv
Gọi nội bộ __invert__
trên Series.
operator.inv(mask)
0 False
1 False
2 True
dtype: bool
np.logical_not
Đây là biến thể numpy.
np.logical_not(mask)
0 False
1 False
2 True
dtype: bool
Lưu ý, np.logical_and
có thể được thay thế cho np.bitwise_and
, logical_or
với bitwise_or
và logical_not
với invert
.