come si filtrano i dataframe dei panda in base a più colonne


99

Per filtrare un dataframe (df) in base a una singola colonna, se consideriamo i dati con maschi e femmine potremmo:

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

Domanda 1 - E se i dati coprissero più anni e volessi vedere solo i maschi per il 2014?

In altre lingue potrei fare qualcosa come:

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

(tranne che voglio farlo e ottenere un sottoinsieme del dataframe originale in un nuovo oggetto dataframe)

Domanda 2. Come faccio a farlo in un ciclo e creo un oggetto dataframe per ogni set univoco di anno e sesso (ad esempio, un df per: 2013-Male, 2013-Female, 2014-Male e 2014-Female

for y in year:

for g in gender:

df = .....

Vuoi filtrarlo o raggrupparlo ? Se desideri creare un DataFrame separato per ogni set univoco di anno e sesso, guarda groupby.
BrenBarn

1
Questa risposta offre una panoramica completa dell'indicizzazione booleana e degli operatori logici nei panda.
cs95

Risposte:


169

Utilizzando l' &operatore, non dimenticare di racchiudere le sotto-istruzioni con ():

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

Per memorizzare i tuoi dataframe dictutilizzando un ciclo for:

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

MODIFICARE:

Una demo per il tuo getDF:

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

print genDF(dic, 'male', 2014)

ottima risposta zhangxaochen - potresti modificare la tua risposta per mostrare in fondo come potresti fare un ciclo for, che crea i dataframe (con dati su anno e sesso) ma li aggiunge a un dizionario in modo che possano essere consultati in seguito con il mio metodo getDF? def GetDF (dict, key): return dict [key]
yoshiserry

@yoshiserry com'è il keytuo getDF? un singolo parametro o una tupla di chiavi? sii specifico per favore;)
zhangxaochen

ciao è una singola chiave, solo una parola, che corrisponderebbe al sesso (maschio o femmina) o all'anno (13, 14) Non sapevo che potessi avere una tupla di chiavi. Potresti condividere un esempio di quando e come lo faresti?
yoshiserry

potresti dare un'occhiata anche a questa domanda. Mi sento come se potessi rispondere. Si riferisce di nuovo ai dataframe dei panda. stackoverflow.com/questions/22086619/...
yoshiserry

1
Si noti che Gendere Yeardovrebbero essere entrambe stringhe, ovvero 'Gender'e 'Year'.
Steven C. Howell

22

Per funzioni booleane più generali che vorresti usare come filtro e che dipendono da più di una colonna, puoi usare:

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

dove f è una funzione che viene applicata a ogni coppia di elementi (x1, x2) da col_1 e col_2 e restituisce True o False a seconda di qualsiasi condizione si desideri (x1, x2).


11

Inizia da panda 0.13 , questo è il modo più efficiente.

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

1
Perché dovrebbe essere più efficiente della risposta accettata?
Bouncner

@Bouncner lo verifica solo contro la risposta votata.
redreamality

4
Questa risposta potrebbe essere migliorata mostrando il benchmark
nardeas

6

Nel caso qualcuno si chieda qual è il modo più veloce per filtrare (la risposta accettata o quella di @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)]

Risultati per 100.000 righe:

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)

Risultati per 10.000.000 di righe:

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)

Quindi i risultati dipendono dalle dimensioni e dai dati. Sul mio laptop, query()diventa più veloce dopo 500k righe. Inoltre, la ricerca di stringhe in Year=="2014"ha un overhead non necessario ( Year==2014è più veloce).


1

Puoi creare la tua funzione di filtro utilizzando queryin pandas. Qui hai il filtraggio dei dfrisultati in base a tutti i kwargsparametri. Non dimenticare di aggiungere alcuni validatori ( kwargsfiltraggio) per ottenere la tua funzione di filtro 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)

Grazie per l'elegante soluzione! Penso che sia il migliore di tutto il resto. Combina l'efficienza dell'utilizzo di query con la versatilità di averla come funzione.
A Merii il

0

Puoi filtrare per più colonne (più di due) utilizzando l' np.logical_andoperatore per sostituire &(o np.logical_orper sostituire |)

Ecco una funzione di esempio che fa il lavoro, se fornisci valori target per più campi. Puoi adattarlo a diversi tipi di filtri e quant'altro:

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

Utilizzo:

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

filter_df(df, {
    'a': [1, 2, 3],
    'b': [1, 2, 4]
})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.