¿Cómo se filtran los marcos de datos de pandas por varias columnas?


100

Para filtrar un marco de datos (df) por una sola columna, si consideramos los datos con hombres y mujeres, podríamos:

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

Pregunta 1: ¿Pero qué pasa si los datos abarcan varios años y solo quisiera ver hombres en 2014?

En otros idiomas, podría hacer algo como:

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

(excepto que quiero hacer esto y obtener un subconjunto del marco de datos original en un nuevo objeto de marco de datos)

Pregunta 2. ¿Cómo hago esto en un bucle y creo un objeto de marco de datos para cada conjunto único de año y género (es decir, un df para: 2013-Masculino, 2013-Femenino, 2014-Masculino y 2014-Femenino

for y in year:

for g in gender:

df = .....

¿Quieres filtrarlo o agruparlo ? Si desea crear un DataFrame separado para cada conjunto único de año y género, mire groupby.
BrenBarn

1
Esta respuesta brinda una descripción general completa de la indexación booleana y los operadores lógicos en pandas.
cs95

Respuestas:


172

Usando el &operador, no olvide envolver las sub-declaraciones con ():

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

Para almacenar sus marcos de datos en un dictbucle 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

EDITAR:

Una demostración para tu getDF:

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

print genDF(dic, 'male', 2014)

gran respuesta zhangxaochen: ¿podría editar su respuesta para mostrar en la parte inferior cómo podría hacer un bucle for, que crea los marcos de datos (con datos de año y género) pero los agrega a un diccionario para que se pueda acceder a ellos más tarde con mi método getDF? def GetDF (dict, key): return dict [key]
yoshiserry

@yoshiserry ¿cómo es keytu getDF? ¿Un solo parámetro o una tupla de claves? sea ​​específico por
favor

hola, es una sola clave, solo una palabra, que correspondería al género (masculino o femenino) o al año (13, 14). No sabía que podía tener una tupla de claves. ¿Podría compartir un ejemplo de cuándo y cómo haría esto?
yoshiserry

¿Podrías echarle un vistazo a esta pregunta también? Siento que podrías responderlo. Se relaciona de nuevo con los marcos de datos de pandas. stackoverflow.com/questions/22086619/…
yoshiserry

1
Tenga en cuenta que Gendery Yeardeben ser cadenas, es decir, 'Gender'y 'Year'.
Steven C. Howell

22

Para funciones booleanas más generales que le gustaría usar como filtro y que dependen de más de una columna, puede usar:

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

donde f es una función que se aplica a cada par de elementos (x1, x2) de col_1 y col_2 y devuelve Verdadero o Falso dependiendo de cualquier condición que desee en (x1, x2).


11

Comience desde pandas 0.13 , esta es la forma más eficiente.

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

1
¿Por qué debería ser esto más eficiente que la respuesta aceptada?
Bouncner

@Bouncner simplemente verifíquelo con la respuesta más votada.
reamalidad

5
Esta respuesta podría mejorarse mostrando el punto de referencia
nardeas

8

En caso de que alguien se pregunte cuál es la forma más rápida de filtrar (la respuesta aceptada o la de @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)]

Resultados de 100.000 filas:

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)

Resultados para 10,000,000 filas:

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)

Entonces, los resultados dependen del tamaño y los datos. En mi computadora portátil, se query()vuelve más rápido después de 500k filas. Además, la búsqueda de cadenas Year=="2014"tiene una sobrecarga innecesaria ( Year==2014es más rápida).


1
Sin embargo, creo que la querysintaxis es más ordenada y cercana a SQL, lo que la hace agradable para los datos desde entonces. Lo bueno del pastel es que es más rápido con muchas filas :)
csgroen

1

Puede crear su propia función de filtro usando queryin pandas. Aquí tienes filtrado de dfresultados por todos los kwargsparámetros. No olvide agregar algunos validadores ( kwargsfiltrado) para obtener la función de filtro por su cuenta 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)

¡Gracias por la elegante solución! Creo que es el mejor de todos los demás. Combina la eficacia de utilizar la consulta con la versatilidad de tenerla como función.
A Merii

0

Puede filtrar por varias columnas (más de dos) utilizando el np.logical_andoperador para reemplazar &(o np.logical_orreemplazar |)

Aquí hay una función de ejemplo que hace el trabajo, si proporciona valores de destino para varios campos. Puede adaptarlo para diferentes tipos de filtrado y demás:

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

Uso:

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

filter_df(df, {
    'a': [1, 2, 3],
    'b': [1, 2, 4]
})
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.