แพนด้า: หลายเงื่อนไขในขณะที่สร้างดัชนีกรอบข้อมูล - พฤติกรรมที่ไม่คาดคิด


135

ฉันกำลังกรองแถวในดาต้าเฟรมตามค่าในสองคอลัมน์

ด้วยเหตุผลบางประการตัวดำเนินการ OR มีพฤติกรรมเหมือนที่ฉันคาดหวังให้ตัวดำเนินการ 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 ในทางกลับกันโอเปอเรเตอร์ OR ต้องการให้ทั้งสองค่าเท่ากับ -1 เพื่อวางค่าเหล่านี้

ถูกตัอง. จำไว้ว่าคุณกำลังเขียนเงื่อนไขในแง่ของสิ่งที่คุณต้องการเก็บไว้ไม่ใช่ในแง่ของสิ่งที่คุณต้องการทิ้ง สำหรับdf1:

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

คุณกำลังพูดว่า "เก็บแถวที่df.aไม่ใช่ -1 และdf.bไม่ใช่ -1" ซึ่งเหมือนกับการทิ้งทุกแถวที่มีค่าอย่างน้อย 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').
Phillip Cloud

6
เกิดขึ้นเพื่อทราบว่าทำไมหมีแพนด้าถึงต้องการ&และ|มากกว่าandและor?
เตา

3
@stoves: ในโค้ด Python ปกติandและorมีความหมาย Python พื้นฐานที่ไม่สามารถแก้ไขได้ &และ|ในทางกลับกันมีวิธีการพิเศษที่เกี่ยวข้องซึ่งควบคุมพฤติกรรมของพวกเขา (แน่นอนในสตริงการค้นหาเราสามารถใช้การแยกวิเคราะห์ที่เราต้องการได้ฟรี)
DSM

น่าสนใจดูเหมือนdf[True & False]ล้มเหลว แต่df[(True) & (False)]ประสบความสำเร็จ (ไม่ได้ทดสอบในตัวอย่างนี้)
3pitt

1
เป็นไปได้ไหมที่จะทำลายไวยากรณ์ประเภทนี้ในหลายบรรทัด PEP8 ส่วนใหญ่จะเป็นอย่างไร
tommy.carstensen

42

คุณสามารถใช้query ()เช่น:

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

ฉันมีสถานการณ์ที่ฉันคิดว่าไวยากรณ์นี้เหมาะสมกว่าเช่น: df.query ('' (a == 4 & b! = 2) | c == 3 ")
Aus_10

9

ทฤษฎีลอจิกทางคณิตศาสตร์เล็กน้อยที่นี่:

"NOT a AND NOT b"เหมือนกับ"NOT (a หรือ b)"ดังนั้น:

"a NOT -1 และ b NOT -1" เทียบเท่ากับ "NOT (a คือ -1 หรือ b คือ -1)"ซึ่งตรงข้าม (ส่วนเสริม) ของ"(a คือ -1 หรือ b คือ -1)"-1)"

ดังนั้นหากคุณต้องการผลลัพธ์ตรงกันข้าม df1 และ df2 ควรเป็นดังนี้:

df1 = df[(df.a != -1) & (df.b != -1)]
df2 = df[(df.a == -1) | (df.b == -1)]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.