Limpiar datos sucios con pandas significa identificar y corregir valores nulos, duplicados y tipos de dato incorrectos antes de hacer cualquier análisis.
Los datos reales siempre tienen errores. Un archivo exportado del SAT, del IMSS o de un sistema de ventas de Liverpool casi nunca llega perfecto. Aprender a limpiarlos es la habilidad más importante en el análisis de datos.
¿Qué es un dato "sucio"?
Un dato sucio es cualquier valor que impide un análisis correcto. Existen tres tipos principales:
| Tipo de problema | Ejemplo real |
|---|---|
| Valor nulo | Una celda vacía en la columna salario |
| Duplicado | El mismo empleado registrado dos veces |
| Tipo incorrecto | La columna precio guardada como texto, no como número |
Cada tipo requiere una técnica distinta. Las siguientes secciones cubren cada una paso a paso.
Cómo detectar valores nulos
Un valor nulo es una celda sin información. En pandas se representa como NaN (Not a Number).
Usa .isnull().sum() para contar los nulos por columna:
import pandas as pd
df = pd.read_csv("empleados_bimbo.csv", encoding="latin-1")
print(df.isnull().sum())
Resultado:
nombre 0
departamento 3
salario 7
fecha_alta 1
dtype: int64
Eso significa que la columna salario tiene 7 celdas vacías. Antes de calcular promedios o totales, debes decidir qué hacer con esas celdas.
Opción 1: Eliminar filas con nulos
Usa .dropna() para eliminar cualquier fila que tenga al menos un valor nulo:
df_limpio = df.dropna()
print(df_limpio.shape)
Esta opción funciona bien cuando los nulos son pocos y no afectan el análisis.
Opción 2: Rellenar nulos con un valor
Usa .fillna() para sustituir los nulos por un valor específico:
# Rellenar salarios nulos con el promedio del grupo
promedio_salario = df["salario"].mean()
df["salario"] = df["salario"].fillna(promedio_salario)
En un contexto de FEMSA, si tienes registros de vendedores sin salario capturado, rellenar con el promedio evita perder esas filas.
Opción 3: Rellenar con el valor anterior
Usa method="ffill" (forward fill) cuando los datos son secuenciales, como fechas de pedidos:
df["fecha_entrega"] = df["fecha_entrega"].fillna(method="ffill")
Cómo eliminar duplicados
Un duplicado es una fila idéntica o casi idéntica a otra. Ocurre cuando dos sistemas registran el mismo evento, o cuando alguien importa un archivo dos veces.
Usa .duplicated() para detectarlos:
print(df.duplicated().sum())
Si el resultado es mayor que cero, tienes filas repetidas. Elimínalas con .drop_duplicates():
df = df.drop_duplicates()
print(df.shape)
Duplicados parciales
A veces solo quieres verificar si hay duplicados en una columna específica. Por ejemplo, en una base de clientes de Mercado Libre, el campo id_cliente no debe repetirse:
duplicados_id = df[df.duplicated(subset=["id_cliente"], keep=False)]
print(duplicados_id)
El parámetro keep=False muestra todas las filas duplicadas, no solo la segunda. Eso te ayuda a revisar cuál versión conservar.
Cómo corregir tipos de dato incorrectos
Un tipo de dato incorrecto ocurre cuando pandas interpreta mal una columna. La columna precio puede quedar como object (texto) si tiene comas o signos de peso.
Verifica los tipos con .dtypes:
print(df.dtypes)
Resultado típico con datos sucios:
producto object
precio object
cantidad object
fecha_venta object
dtype: object
Todas las columnas quedaron como texto. Eso impide hacer sumas o promedios.
Convertir texto a número
Usa pd.to_numeric() para convertir una columna a número. El parámetro errors="coerce" convierte los valores que no se pueden transformar en NaN, en lugar de generar un error:
df["precio"] = pd.to_numeric(df["precio"], errors="coerce")
df["cantidad"] = pd.to_numeric(df["cantidad"], errors="coerce")
Limpiar texto antes de convertir
Si la columna precio contiene valores como "$1,250" o "1250.50 MXN", primero debes limpiar el texto:
df["precio"] = df["precio"].str.replace("$", "", regex=False)
df["precio"] = df["precio"].str.replace(",", "", regex=False)
df["precio"] = pd.to_numeric(df["precio"], errors="coerce")
Después de estos tres pasos, la columna precio queda como número flotante y puedes operar con ella.
Convertir texto a fecha
Usa pd.to_datetime() para columnas de fechas:
df["fecha_venta"] = pd.to_datetime(df["fecha_venta"], dayfirst=True, errors="coerce")
El parámetro dayfirst=True es importante en México, donde las fechas se escriben como DD/MM/AAAA y no como MM/DD/AAAA.
Ejemplo completo: limpieza de ventas de una tienda Liverpool
Supón que tienes un archivo ventas_liverpool.csv con estos problemas:
- Columna
precioen texto con signos de peso - Columna
fecha_ventaen formatoDD/MM/AAAA - Algunos registros duplicados
- Valores nulos en
sucursal
import pandas as pd
# Cargar datos
df = pd.read_csv("ventas_liverpool.csv", encoding="latin-1")
# Paso 1: Ver el estado inicial
print(df.info())
print(df.isnull().sum())
# Paso 2: Eliminar duplicados
df = df.drop_duplicates()
# Paso 3: Rellenar nulos en sucursal
df["sucursal"] = df["sucursal"].fillna("Sin asignar")
# Paso 4: Limpiar y convertir precio
df["precio"] = df["precio"].str.replace("$", "", regex=False)
df["precio"] = df["precio"].str.replace(",", "", regex=False)
df["precio"] = pd.to_numeric(df["precio"], errors="coerce")
# Paso 5: Convertir fecha
df["fecha_venta"] = pd.to_datetime(df["fecha_venta"], dayfirst=True, errors="coerce")
# Paso 6: Verificar resultado
print(df.dtypes)
print(df.isnull().sum())
# Calcular ingreso total
df["total"] = df["precio"] * df["cantidad"]
print(df["total"].sum())
Resultado esperado en consola:
precio float64
cantidad float64
fecha_venta datetime64[ns]
sucursal object
nulos restantes: 0
Ingreso total: $4,872,500
Ese flujo de seis pasos cubre el 90% de los problemas de limpieza en datos reales.
Errores comunes
Error 1: Eliminar nulos sin analizar primero.
Si usas .dropna() sin revisar cuántas filas afectas, puedes perder datos importantes. Siempre revisa el porcentaje de nulos antes de decidir.
Error 2: Olvidar reasignar la columna. Muchas operaciones en pandas no modifican el DataFrame original. Debes reasignar:
# INCORRECTO — no guarda el cambio
df["precio"].fillna(0)
# CORRECTO
df["precio"] = df["precio"].fillna(0)
Error 3: Convertir fechas sin especificar el formato.
Sin dayfirst=True, pandas puede interpretar 05/04/2024 como 5 de abril en lugar de 4 de mayo. En México eso genera errores silenciosos que arruinan análisis de tendencias.
Error 4: Limpiar texto en el orden equivocado.
Siempre elimina caracteres especiales antes de convertir con pd.to_numeric(). Si conviertes primero, obtendrás NaN en todos los valores con signo de peso.
Referencia rápida de funciones de limpieza
| Función | Uso principal |
|---|---|
.isnull().sum() |
Contar nulos por columna |
.dropna() |
Eliminar filas con nulos |
.fillna(valor) |
Rellenar nulos con un valor |
.drop_duplicates() |
Eliminar filas duplicadas |
.duplicated(subset=[...]) |
Detectar duplicados en columnas específicas |
pd.to_numeric() |
Convertir texto a número |
pd.to_datetime() |
Convertir texto a fecha |
.str.replace() |
Limpiar caracteres no deseados en texto |
.dtypes |
Ver el tipo de dato de cada columna |
Lo que debes recordar
- Siempre revisa
.isnull().sum()y.dtypesjusto después de cargar cualquier archivo. Esos dos comandos revelan los problemas más comunes. - Usa
.fillna()cuando perder filas afecte tu análisis; usa.dropna()solo cuando los nulos sean pocos y aleatorios. - Limpia el texto con
.str.replace()antes de convertir conpd.to_numeric()opd.to_datetime(). - En México, las fechas van en formato
DD/MM/AAAA: siempre usadayfirst=Truepara evitar errores silenciosos. - Reasigna siempre el resultado de tus transformaciones:
df["columna"] = df["columna"].fillna(...)no es opcional.