HOWTO · Pandas

Filtrar filas de un DataFrame de pandas por valores de columna

Filtra filas de un DataFrame de pandas con máscaras booleanas, loc, isin, between, pruebas de texto y nulos o query.

En esta página

Filtrar consiste en crear un valor booleano por fila y conservar las filas cuyo valor es True. La forma general más clara es df.loc[condición]; el segundo argumento permite seleccionar también las columnas de salida.

Crear el DataFrame de ejemplo

La tabla incluye texto, números, fechas y un producto ausente. Los ejemplos posteriores reutilizan orders. El índice original se conserva; usa .reset_index(drop=True) solo si necesitas uno nuevo.

import pandas as pd

orders = pd.DataFrame(
    {
        "order_id": [101, 102, 103, 104, 105, 106],
        "region": ["East", "West", "East", "North", "West", "East"],
        "product": ["Desk", "Chair", "Desk lamp", "Desk", None, "Chair"],
        "sales": [450, 275, 125, 700, 320, 410],
        "status": ["paid", "pending", "paid", "paid", "cancelled", "pending"],
        "ordered_at": pd.to_datetime(["2026-08-01", "2026-08-03", "2026-08-08", "2026-08-11", "2026-08-14", "2026-08-18"]),
    }
)

Filtrar filas por un valor de columna

Comparar una Series genera la máscara. Los corchetes simples seleccionan las mismas filas, pero .loc expresa mejor la selección simultánea de filas y columnas. Usa != para excluir una coincidencia e isna() o notna() para nulos.

east_orders = orders.loc[orders["region"] == "East"]
print(east_orders[["order_id", "region", "sales"]].to_string(index=False))

Salida:

 order_id region  sales
      101   East    450
      103   East    125
      106   East    410
large_orders = orders.loc[orders["sales"] >= 400, ["order_id", "sales"]]
print(large_orders.to_string(index=False))

Salida:

 order_id  sales
      101    450
      104    700
      106    410

Combinar varias condiciones

Combina condiciones elemento a elemento con &, | y ~, encerrando cada comparación entre paréntesis. and y or de Python esperan un único booleano y provocan el error de verdad ambigua con una Series.

mask = (orders["region"] == "East") & (orders["sales"] >= 400)
result = orders.loc[mask, ["order_id", "region", "sales"]]
print(result.to_string(index=False))

Salida:

 order_id region  sales
      101   East    450
      106   East    410
mask = (orders["status"] == "paid") | (orders["sales"] > 600)
result = orders.loc[mask, ["order_id", "status", "sales"]]
# Raises ValueError: The truth value of a Series is ambiguous.
orders.loc[(orders["region"] == "East") and (orders["sales"] >= 400)]

Filtrar por una lista de valores

Series.isin() evita cadenas de comparaciones. Recibe una lista u otra colección similar, no una cadena suelta. Para excluir valores, aplica ~ al resultado completo de isin().

allowed = ["East", "West"]
result = orders.loc[orders["region"].isin(allowed), ["order_id", "region"]]
print(result.to_string(index=False))

Salida:

 order_id region
      101   East
      102   West
      103   East
      105   West
      106   East
excluded = ["cancelled", "pending"]
paid_only = orders.loc[~orders["status"].isin(excluded)]

Filtrar intervalos y fechas

between() incluye ambos extremos por defecto y también funciona con fechas convertidas mediante pd.to_datetime(). En datos con zona horaria, las fechas límite deben ser compatibles.

mid_value = orders.loc[orders["sales"].between(300, 500), ["order_id", "sales"]]
print(mid_value.to_string(index=False))

Salida:

 order_id  sales
      101    450
      105    320
      106    410
date_mask = orders["ordered_at"].between("2026-08-03", "2026-08-14")
result = orders.loc[date_mask, ["order_id", "ordered_at"]]

Filtrar valores ausentes o presentes

isna() selecciona None, NaN y NaT; notna() exige un valor presente. Una cadena vacía no es nula automáticamente y debe normalizarse o comprobarse por separado.

missing_product = orders.loc[orders["product"].isna(), ["order_id", "product"]]
present_product = orders.loc[orders["product"].notna()]
print(missing_product.to_string(index=False))

Salida:

 order_id product
      105    None

Filtrar valores de texto

str.contains() produce una máscara vectorizada. regex=False busca texto literal, case=False ignora mayúsculas y na=False decide que los textos ausentes no coinciden.

has_desk = orders["product"].str.contains("desk", case=False, regex=False, na=False)
result = orders.loc[has_desk, ["order_id", "product"]]
print(result.to_string(index=False))

Salida:

 order_id   product
      101      Desk
      103 Desk lamp
      104      Desk

Usar DataFrame.query() para expresiones legibles

En query(), @ referencia una variable local y los nombres de columna con espacios requieren comillas invertidas. No concatenes entradas no confiables: la expresión se evalúa y puede ejecutar código.

minimum_sales = 400
result = orders.query("region == 'East' and sales >= @minimum_sales")
print(result[["order_id", "region", "sales"]].to_string(index=False))

Salida:

 order_id region  sales
      101   East    450
      106   East    410

Elegir entre .loc, corchetes y query()

Usa .loc como opción general, corchetes para una selección breve de filas y query() cuando una expresión controlada sea más legible. Añade .copy() antes de modificar un resultado independiente.

east_orders = orders.loc[orders["region"] == "East"].copy()
east_orders["sales_with_tax"] = east_orders["sales"] * 1.2

Evitar sorpresas de alineación y tipos

Las máscaras se alinean por índice. Créala desde el mismo DataFrame o realinéala deliberadamente. Convierte texto numérico o fechas antes de comparar y normaliza texto solo si la regla lo requiere.

Reutilizar y depurar máscaras booleanas

Una máscara con nombre puede contarse, inspeccionarse y probarse. Cero coincidencias devuelve un DataFrame vacío válido. DataFrame.filter() selecciona etiquetas del eje, no filas por valores de celdas.

Filtrar sin modificar los datos de origen

Para cambiar el original, asigna mediante .loc; para trabajar aparte, crea una copia. Esta decisión explícita evita depender de la indexación encadenada o de si un objeto comparte memoria.

DataFrame.loc, Series.isin, Series.between, Series.str.contains, DataFrame.query