TLDR; Operator logis di Panda adalah &
, |
dan ~
, dan tanda kurung (...)
penting!
Operator Python and
, or
dan not
logis dirancang untuk bekerja dengan skalar. Jadi Pandas harus melakukan yang lebih baik dan mengesampingkan operator bitwise untuk mencapai versi fungsionalitas vektor (elemen-bijaksana).
Jadi berikut ini di python ( exp1
danexp2
ekspresi yang mengevaluasi ke hasil boolean) ...
exp1 and exp2 # Logical AND
exp1 or exp2 # Logical OR
not exp1 # Logical NOT
... akan diterjemahkan ke ...
exp1 & exp2 # Element-wise logical AND
exp1 | exp2 # Element-wise logical OR
~exp1 # Element-wise logical NOT
untuk panda.
Jika dalam proses melakukan operasi logis Anda mendapatkan ValueError
, maka Anda harus menggunakan tanda kurung untuk pengelompokan:
(exp1) op (exp2)
Sebagai contoh,
(df['col1'] == x) & (df['col2'] == y)
Dan seterusnya.
Boolean Indexing : Operasi yang umum adalah menghitung topeng boolean melalui kondisi logis untuk menyaring data. Panda menyediakan tiga operator:&
untuk logika AND,|
untuk logika OR, dan~
untuk logika TIDAK.
Pertimbangkan pengaturan berikut:
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
Logis dan
Untuk df
atas, katakan Anda ingin mengembalikan semua baris di mana A <5 dan B> 5. Ini dilakukan dengan menghitung masker untuk setiap kondisi secara terpisah, dan menggunakan mereka.
&
Operator Bitwise Berlebihan
Sebelum melanjutkan, harap perhatikan kutipan khusus dokumen ini, yang menyatakan
Operasi umum lainnya adalah penggunaan vektor boolean untuk menyaring data. Operator adalah: |
untuk or
, &
untuk and
, dan ~
untuk not
. Ini harus dikelompokkan dengan menggunakan tanda kurung , karena secara default Python akan mengevaluasi ekspresi seperti df.A > 2 & df.B < 3
seperti df.A > (2 &
df.B) < 3
, sementara pesanan evaluasi yang diinginkan adalah (df.A > 2) & (df.B <
3)
.
Jadi, dengan mengingat hal ini, elemen bijaksana logis DAN dapat diimplementasikan dengan operator 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
Dan langkah penyaringan selanjutnya adalah sederhana,
df[(df['A'] < 5) & (df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
Tanda kurung digunakan untuk mengganti urutan presedensi default dari operator bitwise, yang memiliki prioritas lebih tinggi atas operator kondisional <
dan >
. Lihat bagian Prioritas Operator di python docs.
Jika Anda tidak menggunakan tanda kurung, ekspresi dievaluasi salah. Misalnya, jika Anda secara tidak sengaja mencoba sesuatu seperti
df['A'] < 5 & df['B'] > 5
Diurai sebagai
df['A'] < (5 & df['B']) > 5
Yang menjadi,
df['A'] < something_you_dont_want > 5
Yang menjadi (lihat dokumen python pada perbandingan operator dirantai ),
(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)
Yang menjadi,
# Both operands are Series...
something_else_you_dont_want1 and something_else_you_dont_want2
Yang melempar
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Jadi, jangan membuat kesalahan itu! 1
Menghindari Pengelompokan Tanda Kurung
Perbaikan sebenarnya cukup sederhana. Sebagian besar operator memiliki metode terikat yang sesuai untuk DataFrames. Jika masing-masing topeng dibangun menggunakan fungsi alih-alih operator bersyarat, Anda tidak perlu lagi mengelompokkan menurut parens untuk menentukan urutan evaluasi:
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
Lihat bagian tentang Perbandingan Fleksibel. . Untuk meringkas, kami punya
╒════╤════════════╤════════════╕
│ │ Operator │ Function │
╞════╪════════════╪════════════╡
│ 0 │ > │ gt │
├────┼────────────┼────────────┤
│ 1 │ >= │ ge │
├────┼────────────┼────────────┤
│ 2 │ < │ lt │
├────┼────────────┼────────────┤
│ 3 │ <= │ le │
├────┼────────────┼────────────┤
│ 4 │ == │ eq │
├────┼────────────┼────────────┤
│ 5 │ != │ ne │
╘════╧════════════╧════════════╛
Pilihan lain untuk menghindari tanda kurung adalah menggunakan DataFrame.query
(atau eval
):
df.query('A < 5 and B > 5')
A B C
1 3 7 9
3 4 7 6
Saya telah banyak mendokumentasikan query
dan eval
dalam Evaluasi Ekspresi Dinamis dalam panda menggunakan pd.eval () .
operator.and_
Memungkinkan Anda untuk melakukan operasi ini secara fungsional. Panggilan internal Series.__and__
yang terkait dengan operator 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
Anda biasanya tidak membutuhkan ini, tetapi berguna untuk mengetahuinya.
Generalisasi: np.logical_and
(dan logical_and.reduce
)
Alternatif lain adalah menggunakan np.logical_and
, yang juga tidak perlu pengelompokan tanda kurung:
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
adalah ufunc (Fungsi Universal) , dan sebagian besar ufunc memiliki reduce
metode. Ini berarti lebih mudah untuk digeneralisasikan dengan logical_and
jika Anda memiliki beberapa topeng ke AND. Misalnya, untuk DAN topeng m1
dan m2
dan m3
dengan &
, Anda harus melakukannya
m1 & m2 & m3
Namun, opsi yang lebih mudah adalah
np.logical_and.reduce([m1, m2, m3])
Ini sangat kuat, karena memungkinkan Anda membangun di atasnya dengan logika yang lebih kompleks (misalnya, secara dinamis menghasilkan topeng dalam pemahaman daftar dan menambahkan semuanya):
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 - Saya tahu saya mengomel tentang hal ini, tapi tolong tahan dengan saya. Ini adalah kesalahan pemula yang sangat , sangat umum, dan harus dijelaskan dengan seksama.
Logis atau
Untuk yang di df
atas, katakan Anda ingin mengembalikan semua baris tempat A == 3 atau B == 7.
Bitwise Overloaded |
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
Jika Anda belum, baca juga bagian Logical AND di atas, semua peringatan berlaku di sini.
Atau, operasi ini dapat ditentukan dengan
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_
Panggilan di Series.__or__
bawah tenda.
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
Untuk dua kondisi, gunakan 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
Untuk beberapa topeng, gunakan 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
TIDAK logis
Diberi topeng, seperti
mask = pd.Series([True, True, False])
Jika Anda perlu membalikkan setiap nilai boolean (sehingga hasil akhirnya [False, False, True]
), maka Anda dapat menggunakan salah satu metode di bawah ini.
Bitwise ~
~mask
0 False
1 False
2 True
dtype: bool
Sekali lagi, ekspresi perlu di kurung.
~(df['A'] == 3)
0 True
1 False
2 False
3 True
4 True
Name: A, dtype: bool
Ini panggilan internal
mask.__invert__()
0 False
1 False
2 True
dtype: bool
Tetapi jangan menggunakannya secara langsung.
operator.inv
Secara internal memanggil __invert__
Seri.
operator.inv(mask)
0 False
1 False
2 True
dtype: bool
np.logical_not
Ini adalah varian yang numpy.
np.logical_not(mask)
0 False
1 False
2 True
dtype: bool
Catatan, np.logical_and
dapat diganti untuk np.bitwise_and
, logical_or
dengan bitwise_or
, dan logical_not
dengan invert
.