Filtrar Filas en Pandas: Seleccionar Datos por Condición en Python
Updated on
Filtrar filas en DataFrames de pandas es una de las operaciones más comunes en análisis de datos. Ya sea que estés limpiando datos, explorando patrones o preparando conjuntos de datos para aprendizaje automático, necesitas seleccionar filas específicas basadas en condiciones. El desafío es elegir el método correcto entre los múltiples enfoques de filtrado de pandas, cada uno con diferente sintaxis, características de rendimiento y casos de uso.
Muchos científicos de datos luchan con la eficiencia del filtrado, especialmente cuando trabajan con grandes conjuntos de datos o condiciones complejas. Usar el método incorrecto puede ralentizar tu análisis en órdenes de magnitud. Entender cuándo usar indexación booleana versus .query() o .loc[] puede marcar la diferencia entre un script que se ejecuta en segundos versus uno que tarda minutos.
Esta guía cubre todos los métodos de filtrado de pandas con ejemplos prácticos, comparaciones de rendimiento y mejores prácticas. Aprenderás indexación booleana, el método .query(), selección .loc[], la función .where() y el método .filter(). Al final, sabrás exactamente qué enfoque usar para cualquier escenario de filtrado.
Comprender los Métodos de Filtrado de Filas en Pandas
Pandas proporciona cinco métodos principales para filtrar filas de DataFrame, cada uno adecuado para diferentes escenarios:
| Método | Mejor Para | Ejemplo de Sintaxis | Rendimiento |
|---|---|---|---|
| Indexación Booleana | Condiciones simples, legibilidad | df[df['age'] > 25] | Rápido para datos pequeños-medianos |
.query() | Condiciones complejas, basado en strings | df.query('age > 25 and city == "NYC"') | Más rápido para datos grandes |
.loc[] | Basado en etiquetas con condiciones | df.loc[df['age'] > 25, ['name', 'age']] | Selección flexible de columnas |
.where() | Mantener estructura, reemplazar valores | df.where(df['age'] > 25, np.nan) | Preserva forma del DataFrame |
.filter() | Filtrar por nombres de columna/índice | df.filter(like='total', axis=1) | Patrones de nombres columna/índice |
Exploremos cada método con ejemplos detallados.
Indexación Booleana: El Enfoque Más Común
La indexación booleana filtra filas creando una máscara booleana (valores True/False) y aplicándola al DataFrame. Este es el método más intuitivo para principiantes.
import pandas as pd
import numpy as np
# Crear DataFrame de ejemplo
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve'],
'age': [25, 30, 35, 28, 32],
'city': ['NYC', 'LA', 'NYC', 'Chicago', 'LA'],
'salary': [70000, 80000, 90000, 75000, 85000]
})
# Filtrar filas donde age es mayor que 30
filtered = df[df['age'] > 30]
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Ver la máscara booleana
print(df['age'] > 30)
# 0 False
# 1 False
# 2 True
# 3 False
# 4 TrueLa indexación booleana funciona evaluando la condición df['age'] > 30, que devuelve una Serie de valores True/False. Cuando pasas esta máscara al DataFrame con df[mask], pandas devuelve solo las filas donde la máscara es True.
Filtrar con Múltiples Condiciones
Combina múltiples condiciones usando operadores lógicos. Importante: Usa & (y), | (o), ~ (no) en lugar de las palabras clave and, or, not de Python. Siempre envuelve cada condición entre paréntesis.
# Múltiples condiciones con AND
filtered = df[(df['age'] > 25) & (df['city'] == 'NYC')]
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# Múltiples condiciones con OR
filtered = df[(df['age'] > 30) | (df['salary'] > 80000)]
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Operador NOT
filtered = df[~(df['city'] == 'NYC')]
print(filtered)
# name age city salary
# 1 Bob 30 LA 80000
# 3 David 28 Chicago 75000
# 4 Eve 32 LA 85000Usar .isin() para Múltiples Valores
Filtra filas donde una columna coincide con cualquier valor en una lista usando .isin():
# Filtrar filas donde city es NYC o LA
cities = ['NYC', 'LA']
filtered = df[df['city'].isin(cities)]
print(filtered)
# name age city salary
# 0 Alice 25 NYC 70000
# 1 Bob 30 LA 80000
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Inverso: ciudades NO en la lista
filtered = df[~df['city'].isin(cities)]
print(filtered)
# name age city salary
# 3 David 28 Chicago 75000Filtrar con .between()
El método .between() filtra valores dentro de un rango (inclusivo por defecto):
# Filtrar edades entre 28 y 32
filtered = df[df['age'].between(28, 32)]
print(filtered)
# name age city salary
# 1 Bob 30 LA 80000
# 3 David 28 Chicago 75000
# 4 Eve 32 LA 85000
# Límites exclusivos
filtered = df[df['age'].between(28, 32, inclusive='neither')]
print(filtered)
# name age city salary
# 1 Bob 30 LA 80000El Método .query(): Filtrado Basado en Strings
El método .query() acepta una expresión de string, haciéndolo legible para condiciones complejas. Es particularmente eficiente para DataFrames grandes porque usa numexpr para optimización.
# Consulta simple
filtered = df.query('age > 30')
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000
# Múltiples condiciones
filtered = df.query('age > 25 and city == "NYC"')
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# Usar variables con símbolo @
min_age = 30
filtered = df.query('age > @min_age')
print(filtered)
# name age city salary
# 2 Charlie 35 NYC 90000
# 4 Eve 32 LA 85000Expresiones Avanzadas .query()
# Usar .isin() en query
cities = ['NYC', 'LA']
filtered = df.query('city in @cities')
print(filtered)
# Condiciones de rango
filtered = df.query('28 <= age <= 32')
print(filtered)
# Métodos de string
filtered = df.query('city.str.contains("LA")', engine='python')
print(filtered).loc[] para Filtrado Basado en Etiquetas
El indexador .loc[] combina filtrado de filas con selección de columnas. Úsalo cuando necesites columnas específicas de filas filtradas.
# Filtrar filas y seleccionar columnas
filtered = df.loc[df['age'] > 30, ['name', 'age']]
print(filtered)
# name age
# 2 Charlie 35
# 4 Eve 32
# Múltiples condiciones
filtered = df.loc[(df['age'] > 25) & (df['salary'] > 75000), ['name', 'salary']]
print(filtered)
# name salary
# 1 Bob 80000
# 2 Charlie 90000
# 4 Eve 85000
# Todas las columnas
filtered = df.loc[df['city'] == 'NYC', :]
print(filtered)Método .where(): Reemplazo Condicional de Valores
A diferencia de otros métodos, .where() preserva la forma del DataFrame reemplazando valores que no cumplen la condición con NaN (o un valor especificado).
# Mantener valores donde age > 30, reemplazar otros con NaN
result = df.where(df['age'] > 30)
print(result)
# name age city salary
# 0 NaN NaN NaN NaN
# 1 NaN NaN NaN NaN
# 2 Charlie 35.0 NYC 90000.0
# 3 NaN NaN NaN NaN
# 4 Eve 32.0 LA 85000.0
# Reemplazar con valor personalizado
result = df.where(df['age'] > 30, 'FILTERED')
print(result)
# Eliminar filas con NaN después de .where()
result = df.where(df['age'] > 30).dropna()
print(result)Método .filter(): Filtrar por Nombres de Columna/Índice
El método .filter() filtra columnas o filas por sus etiquetas (nombres), no por valores. Úsalo para selección de columnas basada en patrones.
# Crear DataFrame con múltiples columnas
df_wide = pd.DataFrame({
'total_sales': [100, 200, 300],
'total_profit': [20, 40, 60],
'monthly_sales': [10, 20, 30],
'yearly_sales': [120, 240, 360],
'region': ['East', 'West', 'North']
})
# Filtrar columnas que contienen 'total'
filtered = df_wide.filter(like='total')
print(filtered)
# total_sales total_profit
# 0 100 20
# 1 200 40
# 2 300 60
# Filtrar columnas usando regex
filtered = df_wide.filter(regex=r'.*sales$')
print(filtered)
# total_sales monthly_sales yearly_sales
# 0 100 10 120
# 1 200 20 240
# 2 300 30 360
# Filtrar columnas por nombres exactos
filtered = df_wide.filter(items=['total_sales', 'region'])
print(filtered)Filtrar Datos de String
Pandas proporciona métodos de string a través del accessor .str para filtrar columnas de texto.
# Crear DataFrame con datos de texto
df_text = pd.DataFrame({
'name': ['Alice Smith', 'Bob Johnson', 'Charlie Brown', 'David Lee'],
'email': ['alice@gmail.com', 'bob@yahoo.com', 'charlie@gmail.com', 'david@outlook.com']
})
# Filtrar filas donde name contiene 'Smith'
filtered = df_text[df_text['name'].str.contains('Smith')]
print(filtered)
# name email
# 0 Alice Smith alice@gmail.com
# Búsqueda sin distinción de mayúsculas
filtered = df_text[df_text['name'].str.contains('smith', case=False)]
print(filtered)
# Filtrar por dominio de email
filtered = df_text[df_text['email'].str.endswith('gmail.com')]
print(filtered)
# name email
# 0 Alice Smith alice@gmail.com
# 2 Charlie Brown charlie@gmail.com
# Filtrar con regex
filtered = df_text[df_text['name'].str.match(r'^[A-C]')]
print(filtered)Filtrar Valores Nulos y No Nulos
Usa .isna(), .notna(), .isnull() y .notnull() para filtrar basándose en datos faltantes.
# Crear DataFrame con valores faltantes
df_missing = pd.DataFrame({
'A': [1, 2, np.nan, 4],
'B': [5, np.nan, 7, 8],
'C': [9, 10, 11, 12]
})
# Filtrar filas donde columna A no es null
filtered = df_missing[df_missing['A'].notna()]
print(filtered)
# A B C
# 0 1.0 5.0 9
# 1 2.0 NaN 10
# 3 4.0 8.0 12
# Filtrar filas donde CUALQUIER columna es null
filtered = df_missing[df_missing.isna().any(axis=1)]
print(filtered)
# A B C
# 1 2.0 NaN 10
# 2 NaN 7.0 11
# Filtrar filas donde TODAS las columnas no son null
filtered = df_missing[df_missing.notna().all(axis=1)]
print(filtered)
# A B C
# 0 1.0 5.0 9
# 3 4.0 8.0 12Filtrar por Rangos de Fechas
Cuando trabajas con columnas datetime, puedes filtrar por rangos de fechas usando operadores de comparación estándar.
# Crear DataFrame con fechas
df_dates = pd.DataFrame({
'date': pd.date_range('2026-01-01', periods=10, freq='D'),
'value': range(10)
})
# Filtrar fechas después de una fecha específica
filtered = df_dates[df_dates['date'] > '2026-01-05']
print(filtered)
# Filtrar rango de fechas
start_date = '2026-01-03'
end_date = '2026-01-07'
filtered = df_dates[(df_dates['date'] >= start_date) & (df_dates['date'] <= end_date)]
print(filtered)
# Usar .between() para fechas
filtered = df_dates[df_dates['date'].between('2026-01-03', '2026-01-07')]
print(filtered)Comparación de Rendimiento: DataFrames Grandes
Diferentes métodos de filtrado tienen diferentes características de rendimiento. Aquí hay una comparación para un DataFrame con 1 millón de filas:
import time
# Crear DataFrame grande
np.random.seed(42)
df_large = pd.DataFrame({
'A': np.random.randint(0, 100, 1000000),
'B': np.random.randint(0, 100, 1000000),
'C': np.random.choice(['X', 'Y', 'Z'], 1000000)
})
# Indexación booleana
start = time.time()
result = df_large[(df_large['A'] > 50) & (df_large['B'] < 30)]
print(f"Indexación booleana: {time.time() - start:.4f} segundos")
# Método .query()
start = time.time()
result = df_large.query('A > 50 and B < 30')
print(f"Método .query(): {time.time() - start:.4f} segundos")
# Método .loc[]
start = time.time()
result = df_large.loc[(df_large['A'] > 50) & (df_large['B'] < 30)]
print(f"Método .loc[]: {time.time() - start:.4f} segundos")Insights de rendimiento:
- Indexación booleana: Rápida para condiciones simples, más lenta para filtros complejos multi-condición
- .query(): Más rápido para DataFrames grandes con múltiples condiciones (usa optimización numexpr)
- .loc[]: Similar a indexación booleana pero más flexible para selección de columnas
- .where(): Más lento debido al recorrido completo del DataFrame, usar solo cuando necesites preservar la forma
Para conjuntos de datos de más de 100,000 filas con múltiples condiciones, .query() típicamente supera a la indexación booleana en un 20-40%.
Errores Comunes y Cómo Evitarlos
Error 1: Usar 'and' en Lugar de '&'
# INCORRECTO - lanza ValueError
# filtered = df[df['age'] > 25 and df['city'] == 'NYC']
# CORRECTO
filtered = df[(df['age'] > 25) & (df['city'] == 'NYC')]Error 2: Olvidar Paréntesis
# INCORRECTO - problemas de precedencia de operadores
# filtered = df[df['age'] > 25 & df['city'] == 'NYC']
# CORRECTO - envolver cada condición
filtered = df[(df['age'] > 25) & (df['city'] == 'NYC')]Error 3: Modificar DataFrame Original
# Filtrar crea una vista, no una copia
filtered = df[df['age'] > 30]
# INCORRECTO - SettingWithCopyWarning
# filtered['new_col'] = 100
# CORRECTO - crear copia explícita
filtered = df[df['age'] > 30].copy()
filtered['new_col'] = 100Error 4: Filtrado de String sin Manejar NaN
df_with_nan = pd.DataFrame({
'name': ['Alice', np.nan, 'Charlie']
})
# INCORRECTO - lanza error si hay NaN presente
# filtered = df_with_nan[df_with_nan['name'].str.contains('li')]
# CORRECTO - manejar NaN con parámetro na
filtered = df_with_nan[df_with_nan['name'].str.contains('li', na=False)]Visualizar Datos Filtrados con PyGWalker
Después de filtrar tu DataFrame de pandas, visualizar los resultados ayuda a descubrir patrones e insights. PyGWalker (opens in a new tab) transforma DataFrames filtrados en una interfaz interactiva similar a Tableau directamente en notebooks de Python, sin necesidad de exportar datos o escribir código de gráficos complejo.
PyGWalker es particularmente útil cuando exploras conjuntos de datos filtrados porque te permite:
- Arrastrar y soltar columnas para crear gráficos instantáneamente
- Aplicar filtros adicionales visualmente sin escribir código
- Cambiar entre tipos de gráficos (barras, línea, dispersión, mapa de calor) en segundos
- Exportar visualizaciones para informes o presentaciones
import pygwalker as pyg
# Filtrar DataFrame
filtered_df = df[(df['age'] > 25) & (df['salary'] > 75000)]
# Lanzar visualización interactiva
pyg.walk(filtered_df)Esto abre una interfaz interactiva donde puedes crear visualizaciones arrastrando columnas filtradas al constructor de gráficos. Para analistas de datos que trabajan con múltiples condiciones de filtro, PyGWalker elimina el ciclo de iteración de filtrar → graficar → ajustar → volver a graficar.
Preguntas Frecuentes
¿Cómo filtro filas de DataFrame de pandas por condición?
Usa indexación booleana con df[df['column'] > value] para condiciones simples. Para múltiples condiciones, usa & (y), | (o), ~ (no) con paréntesis: df[(df['A'] > 10) & (df['B'] < 20)]. Alternativamente, usa .query() para sintaxis legible: df.query('A > 10 and B < 20').
¿Cuál es la diferencia entre .loc[] e indexación booleana?
La indexación booleana (df[df['col'] > 5]) devuelve todas las columnas para filas filtradas. .loc[] permite selección de columnas simultáneamente: df.loc[df['col'] > 5, ['col1', 'col2']]. Ambos métodos tienen rendimiento similar, pero .loc[] es más explícito y soporta selección de filas basada en etiquetas.
¿Cómo filtrar DataFrame de pandas con múltiples condiciones?
Combina condiciones usando operadores & (y), | (o), ~ (no). Siempre envuelve cada condición entre paréntesis: df[(df['age'] > 25) & (df['city'] == 'NYC') | (df['salary'] > 80000)]. Para condiciones complejas, usa .query(): df.query('age > 25 and (city == "NYC" or salary > 80000)').
¿Cuándo debería usar .query() en lugar de indexación booleana?
Usa .query() para DataFrames grandes (>100k filas) con múltiples condiciones: es 20-40% más rápido debido a la optimización numexpr. También es más legible para condiciones complejas. Usa indexación booleana para filtros simples o cuando necesites máxima compatibilidad (.query() requiere expresiones de string que son más difíciles de depurar).
¿Cómo filtro filas donde el valor de columna está en una lista?
Usa el método .isin(): df[df['city'].isin(['NYC', 'LA', 'Chicago'])]. Para el inverso (no en lista), usa el operador ~: df[~df['city'].isin(['NYC', 'LA'])]. Esto es más eficiente que encadenar múltiples condiciones | para listas grandes.
Conclusión
Filtrar filas de DataFrame de pandas es una habilidad fundamental para el análisis de datos en Python. Ahora entiendes cinco métodos de filtrado: indexación booleana para simplicidad, .query() para rendimiento, .loc[] para selección flexible de columnas, .where() para reemplazo de valores y .filter() para patrones de nombres de columnas.
Conclusiones clave:
- Usa indexación booleana para filtros rápidos y legibles en conjuntos de datos pequeños a medianos
- Elige .query() para conjuntos de datos grandes con condiciones complejas (20-40% más rápido)
- Aplica .loc[] cuando necesites tanto filtrado de filas como selección de columnas
- Recuerda usar operadores
&,|,~en lugar deand,or,not - Siempre envuelve las condiciones entre paréntesis para evitar problemas de precedencia de operadores
Domina estas técnicas de filtrado y manejarás cualquier escenario de selección de datos eficientemente. Para exploración interactiva de datos filtrados, considera usar PyGWalker para visualizar tus resultados sin escribir código de gráficos adicional.