bagaimana Anda memfilter kerangka data panda menurut beberapa kolom

100

Untuk memfilter kerangka data (df) dengan satu kolom, jika kita mempertimbangkan data dengan laki-laki dan perempuan kita mungkin:

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

Pertanyaan 1 - Tetapi bagaimana jika data dalam rentang beberapa tahun dan saya hanya ingin melihat laki-laki untuk tahun 2014?

Dalam bahasa lain saya mungkin melakukan sesuatu seperti:

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

(kecuali saya ingin melakukan ini dan mendapatkan subset dari dataframe asli di objek dataframe baru)

Pertanyaan 2. Bagaimana saya melakukan ini dalam satu lingkaran, dan membuat objek kerangka data untuk setiap set unik tahun dan jenis kelamin (yaitu df untuk: 2013-Pria, 2013-Wanita, 2014-Pria, dan 2014-Wanita

for y in year:

for g in gender:

df = .....
yoshiserry
sumber
Apakah Anda ingin memfilter atau mengelompokkannya ? Jika Anda ingin membuat DataFrame terpisah untuk setiap set unik tahun dan jenis kelamin, lihat groupby.
BrenBarn
1
Jawaban ini memberikan gambaran umum yang komprehensif tentang pengindeksan boolean dan operator logika pada panda.
cs95

Jawaban:

172

Menggunakan &operator, jangan lupa untuk membungkus sub-pernyataan dengan ():

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

Untuk menyimpan dataframe Anda dictmenggunakan 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

EDIT:

Demo untuk Anda getDF:

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

print genDF(dic, 'male', 2014)
zhangxaochen
sumber
jawaban bagus zhangxaochen - dapatkah Anda mengedit jawaban Anda untuk menunjukkan di bagian bawah bagaimana Anda bisa melakukan perulangan for, yang membuat kerangka data (dengan data tahun dan jenis kelamin) tetapi menambahkannya ke kamus sehingga dapat diakses nanti dengan metode getDF saya? def GetDF (dict, key): return dict [key]
yoshiserry
@yoshiserry seperti apa keydi kamu getDF? parameter tunggal atau tuple kunci?
tlg
hai itu kunci tunggal, hanya sebuah kata, yang akan sesuai dengan jenis kelamin (pria, atau wanita) atau tahun (13, 14) Tidak tahu Anda bisa memiliki tupel kunci. Bisakah Anda membagikan contoh kapan dan bagaimana Anda akan melakukan ini?
yoshiserry
bisakah Anda melihat pertanyaan ini juga. Saya merasa Anda bisa menjawabnya. Berhubungan dengan dataframe panda lagi. stackoverflow.com/questions/22086619/…
yoshiserry
1
Perhatikan bahwa Genderdan Yearharus berupa string, yaitu, 'Gender'dan 'Year'.
Steven C. Howell
22

Untuk fungsi boolean yang lebih umum yang ingin Anda gunakan sebagai filter dan bergantung pada lebih dari satu kolom, Anda dapat menggunakan:

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

di mana f adalah fungsi yang diterapkan ke setiap pasangan elemen (x1, x2) dari col_1 dan col_2 dan mengembalikan True atau False tergantung pada kondisi apa pun yang Anda inginkan (x1, x2).

guibor
sumber
11

Mulai dari panda 0.13 , ini cara yang paling efisien.

df.query('Gender=="Male" & Year=="2014" ')
redreamality
sumber
1
Mengapa ini lebih efisien daripada jawaban yang diterima?
Bouncner
@Bouncner baru saja memverifikasinya dengan jawaban pilihan tinggi.
redreamality
5
Jawaban ini dapat ditingkatkan dengan menunjukkan patokan
nardeas
8

Jika seseorang bertanya-tanya apa cara yang lebih cepat untuk memfilter (jawaban yang diterima atau yang dari @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)]

Hasil untuk 100.000 baris:

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)

Hasil untuk 10.000.000 baris:

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)

Jadi hasilnya tergantung pada ukuran dan datanya. Di laptop saya, query()semakin cepat setelah 500 ribu baris. Selanjutnya, pencarian string Year=="2014"memiliki overhead yang tidak perlu ( Year==2014lebih cepat).

Bouncner
sumber
1
Namun, menurut saya querysintaksnya lebih rapi dan dekat dengan SQL, yang membuatnya bagus untuk data sejak itu. Ceri pada kue adalah lebih cepat dengan banyak baris :)
csgroen
1

Anda dapat membuat fungsi filter Anda sendiri menggunakan querydalam pandas. Di sini Anda memiliki pemfilteran dfhasil berdasarkan semua kwargsparameter. Jangan lupa menambahkan beberapa validator ( kwargspemfilteran) untuk mendapatkan fungsi filter Anda sendiri 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)
Alex
sumber
Terima kasih atas solusi yang elegan! Saya pikir itu yang terbaik dari yang lainnya. Ini menggabungkan efisiensi penggunaan kueri dengan keserbagunaan menjadikannya sebagai fungsi.
A Merii
0

Anda dapat memfilter dengan beberapa kolom (lebih dari dua) dengan menggunakan np.logical_andoperator untuk mengganti &(atau np.logical_ormengganti |)

Berikut adalah contoh fungsi yang melakukan pekerjaan itu, jika Anda memberikan nilai target untuk beberapa bidang. Anda dapat menyesuaikannya untuk berbagai jenis pemfilteran dan yang lainnya:

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()
        ])
    ]

Pemakaian:

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

filter_df(df, {
    'a': [1, 2, 3],
    'b': [1, 2, 4]
})
Tom Bug
sumber