Python - Pandas: cómo seleccionar filas según múltiples criterios (si no es nan y es igual a un valor específico)

CorePress2024-01-25  8

Tengo un marco de datos

índice Calle Casa Edificio 1 A B C 20 a 2 A B C 20 b 3 A B C 21 Yaya 4 BCD 2 1

Necesita crear una selección múltiple a partir de este DataFrame:

Si Calle == str_filter; Si Casa == casa_filtro; Si el edificio == build_filter Y si el edificio no es NULL;

Ya probé df[(df['Street'] == str_filter) & (df['Casa'] == house_filter) & ((df['Edificio'] == build_filter) & (pd.notnull(df['Edificio'])))

Pero no conduce a un resultado que particularmente quiera ver. Tengo que verificar si el valor del edificio no es NaN y, si es verdadero, seleccionar la fila con el número de edificio determinado. Sin embargo, también quiero seleccionar la fila si tiene un valor NaN para el edificio pero también cumple con otros criterios.

Otra idea fue crear listas parar el conjunto de valores de filtro y el conjunto de estos valores que cumplen con los criterios de pd.notnull:

filter_values = [str_filter, house_filter, build_filter] 
notnull_values = [pd.notnull(entry) for entry in filter_values]

Este no cumple con los criterios de rendimiento, porque tengo un DataFrame extremadamente grande y la creación de listas adicionales con filtrado adicional conducirá a un rendimiento superior. La posible solución puede estar en la función df.loc, pero no sé cómo implementarla.

Para resumir, el problema es el siguiente: ¿Cómo crear selección múltiple en pandas con condiciones para valores NaN?

UPD: Parece que la función que tengo que usar es df[... & (df['Building'] == 'a' if pd.notnull(df['Building']))] usando una analogía con el truco de aplicación lambda

¿Tiene un ejemplo de qué tipo de filtro desea aplicar? Mi intuición me dice que esto se podría solucionar con mascarillas.

- Oddaspa

28/03/2021 a las 15:40

@Oddaspa ¡Claro! Quiero encontrar todos los duplicados en determinadas columnas, pero parece que df.duplicated no funciona para entradas con valores NaN. Entonces, bajo filtros me refiero a ciertos valores, es decir, df[(df['Building'] == 'a') & (pd.notnull(df['Edificio'])))]

-velastim

28/03/2021 a las 15:46

Veo que actualizaste la pregunta. ¿Probaste mi respuesta?

- Oddaspa

28/03/2021 a las 16:18



------------------------------------

Como dijiste en un comentario que también tenías problemas con los duplicados, agregué una opción para eliminarlos.

Recreé su conjunto de datos con esto y agregué un duplicado.

df = pd.DataFrame({
    "Street" : ["ABC", "ABC", "ABC", "BCD", "ABC"],
    "House" : [20, 20, 21, 2, 21],
    "Building" : ['a', 'b', np.NaN, 1, np.NaN]
})

Para eliminar duplicados de su conjunto de datos, simplemente puede ejecutar este bloque:

df = df.drop_duplicates()

Estoy asumiendoque su filtro podría ser una lista blanca de cadenas o números que desea incluir en su conjunto de datos final. Por eso me tomé la libertad de definir un filtro como este:

street_filter = ["ABC", "BCD"]

Para limpiar el conjunto de datos, puedes utilizar este método:

def get_mask(df, street_filter, house_filter, building_filter):
  not_na_mask = df['Building'].notna()
  # hopefully smaller df to query
  df = df[not_na_mask]

  street_mask = df['Street'].apply(lambda x: x in street_filter)
  df = df[street_mask]

  house_mask = df['House'].apply(lambda x: x in house_filter)
  df = df[house_mask]

  building_mask = df['Building'].apply(lambda x: x in building_filter)
  return df[building_mask]
Ejemplo
street_filter = ["ABC", "BCD"]
house_filter = [20, 21]
building_filter = ["a"]
get_mask(df, street_filter, house_filter, building_filter)

    Street  House   Building
 0  ABC     20      a



------------------------------------

Una forma bastante sencilla de hacerlo sería esta:

if df[df['Building'].isnull()].empty:
    df[df['Street'] == str_filter][df['House'] == house_filter][df['Building'] == build_filter]
else:
    df[df['Street'] == str_filter][df['House'] == house_filter][df['Building'].isnull()]

¿No estoy seguro de si esto satisfaría sus requisitos de rendimiento?

7

Probé tu código. Funciona perfecto para múltiples condiciones, pero falla cuando intento seleccionar filas con NaN en el campo Edificio

-velastim

28/03/2021 a las 17:05

¿Entonces quieres que el campo Edificio sea igual a NaN? Pensé que querías excluir los valores de NaN. @sailestim

- Tetalesti

28/03/2021 a las 17:07

Recientemente actualicé el código. Solo lo digo en caso de que solo hayas probado el código de mi respuesta anterior.

- Tetalesti

28/03/2021 a las 17:08

¡Gracias! Probé el último. Entonces, todo lo que quiero es solo una simple selección de subconjunto de marco de datos de valores iguales, incluidos los valores de NaN. Tomando mi ejemplo, quiero seleccionar la tercera fila. Si no hubiera ningún valor NaN en el campo Edificio, usaría df[df['Building'] == 'a']. Pero no funciona con NaN, así que tengo que usar algún tipo de excepción como mi UPD en elpregunta: df[(df['Edificio'] == 'a' if pd.notnull(df['Edificio']) else df[' Edificio'] == math.nan ]

-velastim

28/03/2021 a las 17:17

1

Bien, según tengo entendido, desea seleccionar todos los valores NaN en el edificio, pero si no hay ninguno, entonces desea seleccionar del edificio y luego seleccionar dónde [edificio == "Alguna cadena"]. Trabajaré en una respuesta para usted. Tardaré unos minutos.

- Tetalesti

28/03/2021 a las 17:26

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare