วิธีการกรองดาต้าดาต้าแพนด้าโดยใช้ 'ใน' และ 'ไม่ได้อยู่ใน' เช่นใน SQL


432

ฉันจะบรรลุผลเทียบเท่าของ SQL INและได้NOT INอย่างไร

ฉันมีรายการที่มีค่าที่ต้องการ นี่คือสถานการณ์:

df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']

# pseudo-code:
df[df['countries'] not in countries]

วิธีการทำสิ่งนี้ในปัจจุบันของฉันมีดังนี้:

df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = pd.DataFrame({'countries':['UK','China'], 'matched':True})

# IN
df.merge(countries,how='inner',on='countries')

# NOT IN
not_in = df.merge(countries,how='left',on='countries')
not_in = not_in[pd.isnull(not_in['matched'])]

แต่ดูเหมือนว่าจะเป็นกระบองที่น่ากลัว ทุกคนสามารถปรับปรุงได้หรือไม่


1
ฉันคิดว่าทางออกของคุณเป็นทางออกที่ดีที่สุด คุณสามารถครอบคลุม IN, NOT_IN จากหลายคอลัมน์
Bruce Jung

คุณต้องการที่จะทดสอบในคอลัมน์เดียวหรือหลายคอลัมน์?
smci

1
ที่เกี่ยวข้อง (การทำงานภายใน / pandas): Pandas pd.Series.isin ประสิทธิภาพกับชุดกับอาร์เรย์
jpp

คำตอบ:


820

pd.Series.isinคุณสามารถใช้

สำหรับการใช้ "IN": something.isin(somewhere)

หรือสำหรับ "ไม่ได้อยู่": ~something.isin(somewhere)

เป็นตัวอย่างการทำงาน:

>>> df
  countries
0        US
1        UK
2   Germany
3     China
>>> countries
['UK', 'China']
>>> df.countries.isin(countries)
0    False
1     True
2    False
3     True
Name: countries, dtype: bool
>>> df[df.countries.isin(countries)]
  countries
1        UK
3     China
>>> df[~df.countries.isin(countries)]
  countries
0        US
2   Germany

1
เพียงแค่ FYI @LondonRob มีเขาเป็น DataFrame และคุณเป็นซีรี่ส์ DataFrame's isinถูกเพิ่มใน. 13
TomAugspurger

คำแนะนำสำหรับวิธีการทำเช่นนี้กับ pandas 0.12.0? มันเป็นรุ่นที่วางจำหน่ายในปัจจุบัน (บางทีฉันควรจะรอ 0.13 ?!)
LondonRob

หากคุณกำลังจัดการกับอาร์เรย์ 1 มิติ (เช่นในตัวอย่างของคุณ) จากนั้นในบรรทัดแรกคุณจะใช้ Series แทน DataFrame เช่น @DSM ที่ใช้:df = pd.Series({'countries':['US','UK','Germany','China']})
TomAugspurger

2
@TomAugspurger: เหมือนปกติฉันอาจจะพลาดอะไรซักอย่าง ทั้งเราและเขาเป็น df เป็นรายการ สร้าง a , ไม่ใช่, และดูเหมือนว่าจะทำงานได้แม้ใน 0.11.0.dev-14a04dd DataFramecountriesdf[~df.countries.isin(countries)]DataFrameSeries
DSM

7
คำตอบนี้ทำให้คุณสับสนเพราะคุณใช้countriesตัวแปรซ้ำ ทีนี้ OP ทำและมันสืบทอดมา แต่สิ่งที่ทำไม่ดีมาก่อนไม่ได้พิสูจน์ว่ามันทำไม่ดีในตอนนี้
ifly6

63

โซลูชันทางเลือกที่ใช้วิธีการ. แบบสอบถาม () :

In [5]: df.query("countries in @countries")
Out[5]:
  countries
1        UK
3     China

In [6]: df.query("countries not in @countries")
Out[6]:
  countries
0        US
2   Germany

10
@LondonRob queryไม่ได้ทำการทดลองอีกต่อไป
Paul Rougieux

38

วิธีการใช้ 'ใน' และ 'ไม่ได้อยู่ใน' สำหรับ DataFrame นุ่น?

Pandas เสนอวิธีการสองวิธี: Series.isinและDataFrame.isinสำหรับ Series และ DataFrames ตามลำดับ


กรอง DataFrame ตามหนึ่งคอลัมน์ (ยังใช้กับซีรี่ส์)

สถานการณ์ที่พบบ่อยที่สุดคือการใช้isinเงื่อนไขในคอลัมน์ที่ระบุเพื่อกรองแถวใน DataFrame

df = pd.DataFrame({'countries': ['US', 'UK', 'Germany', np.nan, 'China']})
df
  countries
0        US
1        UK
2   Germany
3     China

c1 = ['UK', 'China']             # list
c2 = {'Germany'}                 # set
c3 = pd.Series(['China', 'US'])  # Series
c4 = np.array(['US', 'UK'])      # array

Series.isinยอมรับประเภทต่างๆเป็นอินพุต ต่อไปนี้เป็นวิธีที่ถูกต้องในการได้รับสิ่งที่คุณต้องการ:

df['countries'].isin(c1)

0    False
1     True
2    False
3    False
4     True
Name: countries, dtype: bool

# `in` operation
df[df['countries'].isin(c1)]

  countries
1        UK
4     China

# `not in` operation
df[~df['countries'].isin(c1)]

  countries
0        US
2   Germany
3       NaN

# Filter with `set` (tuples work too)
df[df['countries'].isin(c2)]

  countries
2   Germany

# Filter with another Series
df[df['countries'].isin(c3)]

  countries
0        US
4     China

# Filter with array
df[df['countries'].isin(c4)]

  countries
0        US
1        UK

กรองบนคอลัมน์จำนวนมาก

บางครั้งคุณอาจต้องการใช้การตรวจสอบความเป็นสมาชิกแบบ 'in' กับคำค้นหาบางคำในหลายคอลัมน์

df2 = pd.DataFrame({
    'A': ['x', 'y', 'z', 'q'], 'B': ['w', 'a', np.nan, 'x'], 'C': np.arange(4)})
df2

   A    B  C
0  x    w  0
1  y    a  1
2  z  NaN  2
3  q    x  3

c1 = ['x', 'w', 'p']

หากต้องการใช้isinเงื่อนไขกับทั้งคอลัมน์ "A" และ "B" ให้ใช้DataFrame.isin:

df2[['A', 'B']].isin(c1)

      A      B
0   True   True
1  False  False
2  False  False
3  False   True

จากนี้เพื่อรักษาแถวที่มีคอลัมน์อย่างน้อยหนึ่งคอลัมน์Trueเราสามารถใช้anyตามแกนแรก:

df2[['A', 'B']].isin(c1).any(axis=1)

0     True
1    False
2    False
3     True
dtype: bool

df2[df2[['A', 'B']].isin(c1).any(axis=1)]

   A  B  C
0  x  w  0
3  q  x  3

โปรดทราบว่าหากคุณต้องการค้นหาทุกคอลัมน์คุณเพียงแค่ข้ามขั้นตอนการเลือกคอลัมน์และทำ

df2.isin(c1).any(axis=1)

ในทำนองเดียวกันเมื่อต้องการเก็บแถวที่มีคอลัมน์ทั้งหมดTrueให้ใช้allในลักษณะเดียวกับก่อนหน้านี้

df2[df2[['A', 'B']].isin(c1).all(axis=1)]

   A  B  C
0  x  w  0

Notable Mentions: numpy.isin,, querylist comprehensions (ข้อมูลสตริง)

นอกเหนือไปจากวิธีการที่อธิบายข้างต้นคุณยังสามารถใช้เทียบเท่า numpy.isinnumpy:

# `in` operation
df[np.isin(df['countries'], c1)]

  countries
1        UK
4     China

# `not in` operation
df[np.isin(df['countries'], c1, invert=True)]

  countries
0        US
2   Germany
3       NaN

ทำไมการพิจารณาถึงความคุ้มค่า ฟังก์ชั่น NumPy โดยปกติจะเร็วกว่าแพนด้าเทียบเท่าเพราะค่าใช้จ่ายที่ต่ำกว่า เนื่องจากนี่คือการดำเนินการ elementwise ที่ไม่ได้ขึ้นอยู่กับการจัดตำแหน่งดัชนีมีสถานการณ์น้อยมากที่วิธีการนี้ไม่ได้เป็นทดแทนที่เหมาะสมสำหรับหมีแพนด้าisin

โดยปกติแล้วงานประจำของ Pandas จะวนซ้ำเมื่อทำงานกับสตริงเนื่องจากการทำงานของสตริงนั้นยากต่อการ vectorise มีหลักฐานมากมายที่จะแนะนำว่ารายการความเข้าใจจะเร็วขึ้นที่นี่ . เราหันไปinตรวจสอบทันที

c1_set = set(c1) # Using `in` with `sets` is a constant time operation... 
                 # This doesn't matter for pandas because the implementation differs.
# `in` operation
df[[x in c1_set for x in df['countries']]]

  countries
1        UK
4     China

# `not in` operation
df[[x not in c1_set for x in df['countries']]]

  countries
0        US
2   Germany
3       NaN

อย่างไรก็ตามมีความไม่แน่นอนมากที่จะระบุอย่างไรก็ตามอย่าใช้มันจนกว่าคุณจะรู้ว่าคุณกำลังทำอะไรอยู่

สุดท้ายนี้ยังDataFrame.queryมีคำตอบนี้อีกด้วย FTW numexpr!


ฉันชอบ แต่ถ้าฉันต้องการเปรียบเทียบคอลัมน์ใน df3 นั่นคือคอลัมน์ df1 มันจะมีหน้าตาเป็นอย่างไร?
Arthur D. Howland

12

ฉันมักจะทำการกรองทั่วไปมากกว่าแถวเช่นนี้

criterion = lambda row: row['countries'] not in countries
not_in = df[df.apply(criterion, axis=1)]

10
FYI, นี่ช้ากว่า @DSM soln มากซึ่งเป็น vectorized
Jeff

@ เจฟฟ์ฉันคาดหวัง แต่นั่นคือสิ่งที่ฉันย้อนกลับไปเมื่อฉันต้องการกรองสิ่งที่ไม่มีในแพนด้าโดยตรง (ผมกำลังจะบอกว่า "เหมือน .startwith หรือการจับคู่ regex แต่เพียงพบข้อมูลเกี่ยวกับ Series.str ที่มีทุกที่!)
คอส

7

ฉันต้องการกรองแถว dfbc ที่มี BUSINESS_ID ที่อยู่ใน BUSINESS_ID ของ dfProfilesBusIds ด้วย

dfbc = dfbc[~dfbc['BUSINESS_ID'].isin(dfProfilesBusIds['BUSINESS_ID'])]

5
คุณสามารถลบล้าง isin (เหมือนที่ทำในคำตอบที่ยอมรับ) แทนที่จะเปรียบเทียบกับ False
OneCricketeer

6

การรวบรวมโซลูชันที่เป็นไปได้จากคำตอบ:

สำหรับใน: df[df['A'].isin([3, 6])]

สำหรับไม่ได้อยู่ใน:

  1. df[-df["A"].isin([3, 6])]

  2. df[~df["A"].isin([3, 6])]

  3. df[df["A"].isin([3, 6]) == False]

  4. df[np.logical_not(df["A"].isin([3, 6]))]


3
ซึ่งส่วนใหญ่จะเป็นการทำซ้ำข้อมูลจากคำตอบอื่น ๆ การใช้งานlogical_notนั้นเทียบเท่ากับ~ผู้ปฏิบัติงาน
cs95

3
df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']

ใช้ใน :

df[df.countries.isin(countries)]

ใช้ไม่ได้เหมือนในประเทศที่เหลือ:

df[df.countries.isin([x for x in np.unique(df.countries) if x not in countries])]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.