คุณจะกรองดาต้าเฟรมของแพนด้าตามหลายคอลัมน์ได้อย่างไร


103

ในการกรองดาต้าเฟรม (df) ตามคอลัมน์เดียวหากเราพิจารณาข้อมูลกับชายและหญิงเราอาจ:

males = df[df[Gender]=='Male']

คำถามที่ 1 - แต่จะเกิดอะไรขึ้นถ้าข้อมูลครอบคลุมหลายปีและฉันต้องการดูเฉพาะผู้ชายในปี 2014?

ในภาษาอื่นฉันอาจทำบางสิ่งเช่น:

if A = "Male" and if B = "2014" then 

(ยกเว้นฉันต้องการทำสิ่งนี้และรับส่วนย่อยของ dataframe ดั้งเดิมในวัตถุ dataframe ใหม่)

คำถาม 2. ฉันจะทำสิ่งนี้แบบวนซ้ำได้อย่างไรและสร้างออบเจ็กต์ดาต้าเฟรมสำหรับชุดของปีและเพศที่ไม่ซ้ำกันแต่ละชุด (เช่น df สำหรับ: 2013-Male, 2013-Female, 2014-Male และ 2014-Female

for y in year:

for g in gender:

df = .....

คุณต้องการกรองหรือจัดกลุ่ม ? หากคุณต้องการที่จะสร้าง DataFrame groupbyแยกต่างหากสำหรับแต่ละชุดที่เป็นเอกลักษณ์ของปีและเพศให้ดูที่
BrenBarn

1
คำตอบนี้ให้ภาพรวมที่ครอบคลุมของการสร้างดัชนีบูลีนและตัวดำเนินการเชิงตรรกะในแพนด้า
cs95

คำตอบ:


185

การใช้&ตัวดำเนินการอย่าลืมปิดคำสั่งย่อยด้วย():

males = df[(df[Gender]=='Male') & (df[Year]==2014)]

ในการจัดเก็บดาต้าเฟรมของคุณdictโดยใช้ for loop:

from collections import defaultdict
dic={}
for g in ['male', 'female']:
  dic[g]=defaultdict(dict)
  for y in [2013, 2014]:
    dic[g][y]=df[(df[Gender]==g) & (df[Year]==y)] #store the DataFrames to a dict of dict

แก้ไข:

การสาธิตสำหรับgetDF:

def getDF(dic, gender, year):
  return dic[gender][year]

print genDF(dic, 'male', 2014)

คำตอบที่ยอดเยี่ยม zhangxaochen - คุณสามารถแก้ไขคำตอบของคุณเพื่อแสดงที่ด้านล่างได้อย่างไรว่าคุณจะทำ for loop ซึ่งสร้าง dataframes (พร้อมข้อมูลปีและเพศ) แต่จะเพิ่มลงในพจนานุกรมเพื่อให้สามารถเข้าถึงได้ในภายหลังโดยวิธี getDF ของฉัน def GetDF (dict, key): return dict [key]
yoshiserry

@yoshiserry keyในตัวคุณเป็นgetDFอย่างไร? พารามิเตอร์เดียวหรือทูเพิลของคีย์? เฉพาะเจาะจงกรุณา;)
zhangxaochen

สวัสดีมันเป็นคีย์เดียวคำเดียวที่จะตรงกับเพศ (ชายหรือหญิง) หรือปี (13, 14) ไม่ทราบว่าคุณสามารถมีคีย์จำนวนมากได้ คุณช่วยเล่าตัวอย่างได้ไหมว่าคุณจะทำสิ่งนี้เมื่อใดและอย่างไร
yoshiserry

คุณช่วยดูคำถามนี้ด้วย ฉันรู้สึกว่าคุณสามารถตอบได้ เกี่ยวข้องกับดาต้าเฟรมของแพนด้าอีกครั้ง stackoverflow.com/questions/22086619/…
yoshiserry

1
หมายเหตุว่าGenderและYearทั้งสองควรจะสตริงคือและ'Gender' 'Year'
Steven C. Howell

22

สำหรับฟังก์ชันบูลีนทั่วไปที่คุณต้องการใช้เป็นตัวกรองและขึ้นอยู่กับคอลัมน์มากกว่าหนึ่งคอลัมน์คุณสามารถใช้:

df = df[df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)]

โดยที่ f คือฟังก์ชันที่ใช้กับทุกคู่ขององค์ประกอบ (x1, x2) จาก col_1 และ col_2 และส่งกลับค่า True หรือ False ขึ้นอยู่กับเงื่อนไขที่คุณต้องการบน (x1, x2)


14

เริ่มจากแพนด้า 0.13ซึ่งเป็นวิธีที่มีประสิทธิภาพสูงสุด

df.query('Gender=="Male" & Year=="2014" ')

1
เหตุใดสิ่งนี้จึงมีประสิทธิภาพมากกว่าคำตอบที่ยอมรับ
Bouncner

@Bouncner เพียงยืนยันกับคำตอบที่ได้รับการโหวตสูง
redreamality

6
คำตอบนี้สามารถปรับปรุงได้โดยการแสดงเกณฑ์มาตรฐาน
nardeas

10

ในกรณีที่มีคนสงสัยว่าวิธีการกรองที่เร็วกว่าคืออะไร (คำตอบที่ยอมรับหรือจาก @redreamality):

import pandas as pd
import numpy as np

length = 100_000
df = pd.DataFrame()
df['Year'] = np.random.randint(1950, 2019, size=length)
df['Gender'] = np.random.choice(['Male', 'Female'], length)

%timeit df.query('Gender=="Male" & Year=="2014" ')
%timeit df[(df['Gender']=='Male') & (df['Year']==2014)]

ผลลัพธ์สำหรับ 100,000 แถว:

6.67 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
5.54 ms ± 536 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

ผลลัพธ์สำหรับ 10,000,000 แถว:

326 ms ± 6.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
472 ms ± 25.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

ผลลัพธ์จึงขึ้นอยู่กับขนาดและข้อมูล บนแล็ปท็อปของฉันquery()เร็วขึ้นหลังจาก 500k แถว นอกจากนี้การค้นหาสตริงในYear=="2014"ยังมีค่าใช้จ่ายที่ไม่จำเป็น ( Year==2014เร็วกว่า)


2
อย่างไรก็ตามฉันคิดว่าqueryไวยากรณ์นั้นดีกว่าและใกล้เคียงกับ SQL ซึ่งทำให้ดีสำหรับข้อมูลตั้งแต่นั้นมา เชอรี่บนเค้กมันเร็วกว่าด้วยหลายแถว :)
csgroen

1

คุณสามารถสร้างฟังก์ชั่นตัวกรองของคุณเองโดยใช้ในquery pandasที่นี่คุณมีการกรองdfผลลัพธ์ตามkwargsพารามิเตอร์ทั้งหมด Dont' ลืมที่จะเพิ่มเครื่องมือตรวจสอบบางคน ( kwargsกรอง) dfเพื่อให้ได้ฟังก์ชั่นตัวกรองสำหรับตัวคุณเอง

def filter(df, **kwargs):
    query_list = []
    for key in kwargs.keys():
        query_list.append(f'{key}=="{kwargs[key]}"')
    query = ' & '.join(query_list)
    return df.query(query)

ขอบคุณสำหรับวิธีแก้ปัญหาที่ยอดเยี่ยม! ฉันคิดว่ามันดีที่สุดจากที่เหลือทั้งหมด มันรวมประสิทธิภาพของการใช้แบบสอบถามกับความเก่งกาจของการมีมันเป็นฟังก์ชัน
A Merii

0

คุณสามารถกรองตามหลายคอลัมน์ (มากกว่าสอง) โดยใช้ตัวnp.logical_andดำเนินการเพื่อแทนที่&(หรือnp.logical_orเพื่อแทนที่|)

นี่คือฟังก์ชันตัวอย่างที่ใช้งานได้หากคุณระบุค่าเป้าหมายสำหรับหลายฟิลด์ คุณสามารถปรับให้เข้ากับการกรองประเภทต่างๆและสิ่งที่ไม่:

def filter_df(df, filter_values):
    """Filter df by matching targets for multiple columns.

    Args:
        df (pd.DataFrame): dataframe
        filter_values (None or dict): Dictionary of the form:
                `{<field>: <target_values_list>}`
            used to filter columns data.
    """
    import numpy as np
    if filter_values is None or not filter_values:
        return df
    return df[
        np.logical_and.reduce([
            df[column].isin(target_values) 
            for column, target_values in filter_values.items()
        ])
    ]

การใช้งาน:

df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [1, 2, 3, 4]})

filter_df(df, {
    'a': [1, 2, 3],
    'b': [1, 2, 4]
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.