Limpieza Masiva y Detección de Anomalías con NumPy y Pandas 🧹
Domina el arte de limpiar datasets complejos y detectar valores atípicos (outliers) utilizando las potentes herramientas de vectorización de NumPy y la flexibilidad de Pandas.
Introducción a la Odisea de los Datos Sucios 🧹
En el mundo real de la ciencia de datos, los datasets limpios y perfectamente estructurados son una rareza absoluta. Como analistas e ingenieros de datos, pasamos hasta un 80% de nuestro tiempo valioso en la fase menos glamorosa pero más crucial: la limpieza de datos. Un modelo de machine learning o un análisis estadístico es tan bueno como los datos que lo alimentan (Garbage in, garbage out).
En este tutorial exhaustivo, exploraremos cómo transformar datos caóticos, incompletos y ruidosos en información prístina utilizando la combinación definitiva de Pandas para la manipulación tabular y NumPy para el cálculo numérico ultrarrápido. Vamos a desglosar desde el manejo de valores nulos hasta la detección matemática sofisticada de anomalías.
.copy() para evitar modificar los datos crudos por accidente.Preparación del Entorno y Dataset de Trabajo 🔬
Para poner en práctica estas técnicas, primero necesitamos configurar nuestro entorno de desarrollo e importar las librerías necesarias. Además, vamos a simular un dataset realista que contenga una variedad de problemas típicos: valores faltantes, tipos de datos incorrectos, espacios en blanco accidentales, duplicados y anomalías estadísticas.
import pandas as pd
import numpy as np
# Establecemos una semilla para reproducibilidad
np.random.seed(42)
# Simulando datos caóticos
n_filas = 1000
data = {
"id_cliente": np.arange(100, 100 + n_filas),
"edad": np.random.choice([np.nan, 22, 25, 30, 35, 40, 45, 50, 150, -5], n_filas, p=[0.1, 0.15, 0.15, 0.15, 0.15, 0.1, 0.1, 0.05, 0.02, 0.03]),
"salario": np.random.normal(50000, 15000, n_filas),
"categoria": np.random.choice(["A", "B", "C", " A ", "b", np.nan], n_filas),
"fecha_registro": pd.date_range(start="2021-01-01", periods=n_filas, freq="H")
}
df = pd.DataFrame(data)
# Introducimos algunos valores atípicos extremos en salario
df.loc[np.random.choice(n_filas, 10), "salario"] = 9999999
# Introducimos filas duplicadas deliberadamente
df = pd.concat([df, df.iloc[:15]], ignore_index=True)
Auditoría Inicial y Diagnóstico de Datos 🔍
Antes de aplicar cualquier transformación ciega, debemos auditar el DataFrame para entender la magnitud del problema. La inspección visual y cuantitativa nos guiará sobre qué estrategias implementar.
Métodos Esenciales de Inspección
Utilizaremos una combinación de métodos nativos de Pandas para evaluar la salud de nuestro dataset:
df.info(): Proporciona el uso de memoria y los tipos de datos por columna.df.isnull().sum(): Cuantifica exactamente cuántos valores faltantes existen.df.duplicated().sum(): Revela filas exactamente idénticas.
print("--- INFORMACIÓN GENERAL ---")
print(df.info())
print("\n--- VALORES FALTANTES ---")
print(df.isnull().sum())
print(
f"\n--- FILAS DUPLICADAS: {df.duplicated().sum()} ---"
)
NaN o None en Pandas. A veces se oculta como cadenas vacías (""), espacios en blanco (" ") o valores numéricos centinela (como -999 o 9999).Limpieza y Estandarización de Datos Categóricos y de Texto 📝
Los datos de texto suelen ser la fuente principal de inconsistencias. En nuestro dataset simulado, la columna categoria tiene problemas de espacios iniciales/finales y mayúsculas/minúsculas mezcladas ("A" frente a " A " o "b").
Transformación con el accessor .str
Para solucionar esto, aplicamos operaciones vectorizadas de cadenas:
# Eliminamos espacios en blanco y convertimos todo a mayúsculas
df["categoria"] = df["categoria"].str.strip().str.upper()
# Verificamos las categorías únicas resultantes
print(df["categoria"].value_counts(dropna=False))
Al ejecutar este código, unificamos " A " con "A" y "b" con "B", reduciendo drásticamente la cardinalidad fantasma creada por errores tipográficos.
Estrategias Avanzadas para el Manejo de Valores Faltantes (NaN) 🛠️
En nuestro dataset, la columna edad contiene tanto valores nulos (NaN) como valores absurdos que escapan de la lógica biológica (como -5 y 150).
Paso 1: Convertir valores lógicamente imposibles en NaN
Antes de imputar, debemos limpiar los centinelas ilógicos tratándolos como nulos estándar usando NumPy:
# Reemplazamos edades menores a 0 o mayores a 100 por NaN
df.loc[(df["edad"] < 0) | (df["edad"] > 100), "edad"] = np.nan
Paso 2: Imputación Inteligente
Dependiendo del contexto, podemos eliminar las filas con nulos (dropna) o rellenarlas (fillna). Sin embargo, utilizar la media o la mediana condicional basada en otra columna es una técnica mucho más profesional.
# Imputación utilizando la mediana global para la edad
mediana_edad = df["edad"].median()
df["edad"].fillna(mediana_edad, inplace=True)
¿Cuándo es mejor usar la Media vs. la Mediana?
La media es sensible a valores extremos (outliers), por lo que si tu distribución está sesgada, la media arrastrará el valor imputado. La mediana es robusta ante valores atípicos y suele ser la opción más segura en distribuciones sesgadas.Detección y Tratamiento de Anomalías (Outliers) con NumPy 📊
Los valores atípicos pueden distorsionar completamente los análisis estadísticos y arruinar el rendimiento de modelos predictivos. Utilizaremos dos métodos estadísticos robustos con NumPy y Pandas: el método del Rango Intercuartílico (IQR) y la puntuación Z (Z-score).
Método 1: El Rango Intercuartílico (IQR)
El IQR es excelente para distribuciones no necesariamente normales:
Q1 = df["salario"].quantile(0.25)
Q3 = df["salario"].quantile(0.75)
IQR = Q3 - Q1
# Definimos los límites para considerar un valor como outlier
limite_inferior = Q1 - 1.5 * IQR
limite_superior = Q3 + 1.5 * IQR
# Identificando outliers
outliers_iqr = df(
(df["salario"] < limite_inferior) | (df["salario"] > limite_superior)
)
print(f"Número de outliers detectados por IQR: {outliers_iqr.sum()}")
Método 2: Puntuación Z (Z-score) con NumPy
La puntuación Z mide cuántas desviaciones estándar está un valor de la media. Es muy útil cuando asumimos una distribución aproximadamente normal:
# Calculamos el Z-score utilizando operaciones vectorizadas de NumPy
media_salario = np.mean(df["salario"])
std_salario = np.std(df["salario"])
z_scores = np.abs((df["salario"] - media_salario) / std_salario)
# Filtramos valores con un Z-score mayor a 3
outliers_z = z_scores > 3
print(f"Número de outliers detectados por Z-score: {outliers_z.sum()}")
Optimización y Limpieza de Duplicados en Bloque 🚀
Para finalizar nuestro pipeline de limpieza, debemos deshacernos de las filas duplicadas que introdujimos al inicio del tutorial. Pandas nos permite controlar exactamente qué filas conservar basándonos en subconjuntos de columnas.
# Eliminamos duplicados exactos
df.drop_duplicates(inplace=True)
# Si quisiéramos eliminar duplicados basándonos solo en el ID del cliente:
df.drop_duplicates(subset=["id_cliente"], keep="first", inplace=True)
print(f"Dimensiones finales del DataFrame limpio: {df.shape}")
Resumen del Proceso de Limpieza
A continuación, se presenta una tabla comparativa de las herramientas utilizadas y su propósito principal en el flujo de trabajo:
| Herramienta / Método | Propósito Principal | Cuándo Utilizarlo |
|---|---|---|
| --- | --- | --- |
df.dropna() / fillna() | Gestión de valores nulos | Datos faltantes por errores de captura o sensores |
str.strip() / str.upper() | Estandarización de texto | Limpieza de columnas categóricas con entradas manuales |
| --- | --- | --- |
| Rango IQR | Detección de outliers no paramétricos | Variables con distribuciones sesgadas (ej. ingresos) |
| Z-Score (NumPy) | Detección de outliers paramétricos | Variables con distribución normal o gaussiana |
| --- | --- | --- |
drop_duplicates() | Eliminación de registros repetidos | Auditoría posterior a cruces o uniones de tablas |
Nivel Intermedio-Avanzado Pandas & NumPy
Tutoriales relacionados
- Explorando y Manipulando Datos Jerárquicos con MultiIndex en Pandas 🌲intermediate15 min
- Gestión de Memoria y Rendimiento con Pandas: Estrategias Avanzadasadvanced9 min
- Análisis de Datos Incompletos con Pandas y NumPy: Estrategias para Datos Faltantes 🕵️♀️intermediate20 min
- Análisis Exploratorio de Datos con Pandas: El Arte de Desvelar Secretos Ocultos en tus Datosintermediate20 min
- Análisis de Datos Geográficos y Geoespaciales con Pandas: ¡Dando Vida a tus Mapas! 🗺️intermediate18 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!