Entender por qué el preprocesamiento no es opcional—es el núcleo de cualquier modelo exitoso de ML. Aprender a diagnosticar la salud del conjunto de datos antes de tocar cualquier algoritmo.
"La ciencia de datos es 80% limpieza de datos, 20% quejarse por limpiar datos." — Anónimo
En el mundo real, los datos nunca llegan limpios, ordenados y listos para usar. Llegan con:
NaN, None, "", ?)Consecuencia directa: Alimentar datos sucios a un modelo hace que aprenda patrones incorrectos. Basura Adentro → Basura Afuera.
Antes de hacer cualquier cosa, explora tu conjunto de datos como un detective.
import pandas as pd
# Cargar conjunto de datos
df = pd.read_csv("datos_fraude.csv")
# Vista previa rápida
print(df.head())
print(df.info()) # Tipos de datos y conteos no nulos
print(df.describe()) # Estadísticas descriptivas (solo numéricas)
# Ver valores únicos en columnas categóricas
print(df['tipo_transaccion'].unique())
print(df['pais'].value_counts())
# Verificar valores nulos
print(df.isnull().sum())
import seaborn as sns
import matplotlib.pyplot as plt
# Histograma de una variable numérica
sns.histplot(df['monto_transaccion'], bins=50, kde=True)
plt.title("Distribución del Monto de Transacciones")
plt.show()
# Diagrama de caja para detectar valores atípicos
sns.boxplot(x=df['monto_transaccion'])
plt.title("Diagrama de Caja: Encontrando Valores Atípicos en Montos")
plt.show()
# Gráfico de barras para variables categóricas
sns.countplot(data=df, x='tipo_tarjeta')
plt.title("Distribución de Tipos de Tarjetas")
plt.xticks(rotation=45)
plt.show()
Opción 1: Eliminar filas o columnas
# Eliminar filas con cualquier NaN
df_clean = df.dropna()
# Eliminar columnas con más del 50% de NaN
df_clean = df.dropna(axis=1, thresh=len(df)*0.5)
⚠️ Precaución: Solo recomendable si pierdes pocos puntos de datos. Si eliminas el 30% de tus filas, tu modelo puede volverse sesgado.
Opción 2: Imputación (rellenar con valores)
from sklearn.impute import SimpleImputer
# Imputar media para variables numéricas
imputer_num = SimpleImputer(strategy='mean')
df[['edad', 'monto_transaccion']] = imputer_num.fit_transform(df[['edad', 'monto_transaccion']])
# Imputar moda para variables categóricas
imputer_cat = SimpleImputer(strategy='most_frequent')
df[['tipo_tarjeta']] = imputer_cat.fit_transform(df[['tipo_tarjeta']])
✅ Buena práctica: Usar ColumnTransformer para aplicar diferentes estrategias a diferentes columnas (lo cubriremos en detalle en el Módulo 3).
Un valor que se desvía significativamente del resto de los datos. Puede ser:
Q1 = df['monto_transaccion'].quantile(0.25)
Q3 = df['monto_transaccion'].quantile(0.75)
IQR = Q3 - Q1
limite_inferior = Q1 - 1.5 * IQR
limite_superior = Q3 + 1.5 * IQR
outliers = df[(df['monto_transaccion'] < limite_inferior) | (df['monto_transaccion'] > limite_superior)]
print(f"Valores atípicos detectados: {len(outliers)}")
df['monto_transaccion'] = df['monto_transaccion'].clip(lower=limite_inferior, upper=limite_superior)
df['log_monto'] = np.log1p(df['monto_transaccion']) # log(1+x) para evitar log(0)
Conjunto de datos sugerido: fraud_data.csv (simulado, con columnas: user_id, monto, edad, pais, tipo_tarjeta, hora_dia, es_fraude)
Tareas:
.info() y .describe().monto. Aplicar limitación basada en IQR.edad. ¿Hay valores imposibles (ej., edad < 0 o > 120)? Corregirlos.fraud_clean.csv.