🎯 MÓDULO 6: "Proyecto Final: Construyendo un Sistema de Detección de Fraude con Métricas de Negocio Reales"

Objetivo:

Aplicar TODO lo aprendido en un proyecto integrador realista: desde la carga de datos crudos hasta un modelo evaluado con métricas de negocio, incluyendo preprocesamiento, codificación, escalado, selección de características y validación robusta.


6.1 Conjunto de Datos del Proyecto: transacciones_fraude.csv

Características simuladas:

  • monto_transaccion (float)
  • edad_cliente (int)
  • tipo_tarjeta (categórica: "Visa", "Mastercard", "Amex")
  • pais_origen (categórica)
  • hora_del_dia (int 0-23)
  • dias_desde_ultima_transaccion (int)
  • es_fraude (bool: 0 o 1) → ¡solo 1.5% de fraude!

6.2 Fase 1: Diagnóstico Inicial y Limpieza

# Cargar y explorar
df = pd.read_csv("transacciones_fraude.csv")
print(df.info())
print(df.isnull().sum())

# Imputar edad con mediana, tipo de tarjeta con moda
df['edad_cliente'].fillna(df['edad_cliente'].median(), inplace=True)
df['tipo_tarjeta'].fillna(df['tipo_tarjeta'].mode()[0], inplace=True)

# Limitar monto de transacción usando IQR
Q1 = df['monto_transaccion'].quantile(0.25)
Q3 = df['monto_transaccion'].quantile(0.75)
IQR = Q3 - Q1
lim_inf, lim_sup = Q1 - 1.5*IQR, Q3 + 1.5*IQR
df['monto_transaccion'] = df['monto_transaccion'].clip(lim_inf, lim_sup)

6.3 Fase 2: Codificación y Escalado

# Codificación
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.compose import ColumnTransformer

# Codificación de Etiquetas para variables ordinales (ninguna aquí, pero por si acaso)
# One-Hot para variables categóricas nominales
categorical_features = ['tipo_tarjeta', 'pais_origen']
numeric_features = ['monto_transaccion', 'edad_cliente', 'hora_del_dia', 'dias_desde_ultima_transaccion']

preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), numeric_features),
        ('cat', OneHotEncoder(drop='first', handle_unknown='ignore'), categorical_features)
    ])

X = df.drop('es_fraude', axis=1)
y = df['es_fraude']

X_processed = preprocessor.fit_transform(X)

6.4 Fase 3: Selección de Características y Entrenamiento

from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.model_selection import train_test_split, StratifiedKFold
from sklearn.linear_model import LogisticRegression

# Dividir datos
X_train, X_test, y_train, y_test = train_test_split(X_processed, y, test_size=0.2, stratify=y, random_state=42)

# Selección de características
selector = SelectKBest(score_func=f_classif, k=10)
X_train_selected = selector.fit_transform(X_train, y_train)
X_test_selected = selector.transform(X_test)

# Entrenar modelo
modelo = LogisticRegression(penalty='l2', C=1.0, random_state=42)
modelo.fit(X_train_selected, y_train)

6.5 Fase 4: Evaluación Profunda con Métricas de Negocio

from sklearn.metrics import classification_report, roc_auc_score, confusion_matrix
import seaborn as sns

y_pred = modelo.predict(X_test_selected)
y_proba = modelo.predict_proba(X_test_selected)[:,1]

print("=== REPORTE DE CLASIFICACIÓN ===")
print(classification_report(y_test, y_pred, target_names=['Legítimo', 'Fraude']))

print(f"\nAUC-ROC: {roc_auc_score(y_test, y_proba):.4f}")

# Matriz de confusión
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
            xticklabels=['Legítimo', 'Fraude'],
            yticklabels=['Legítimo', 'Fraude'])
plt.title("Matriz de Confusión - Detección de Fraude")
plt.ylabel("Real")
plt.xlabel("Predicho")
plt.show()

# Validación cruzada para confianza
cv_scores = cross_val_score(modelo, X_train_selected, y_train, cv=StratifiedKFold(5), scoring='roc_auc')
print(f"\nValidación Cruzada AUC-ROC: {cv_scores.mean():.4f} (+/- {cv_scores.std()*2:.4f})")

6.6 Fase 5: Ajuste de Umbral para Maximizar Exhaustividad

from sklearn.metrics import precision_recall_curve

# Encontrar umbral que maximice F1 o exhaustividad
precision, recall, thresholds = precision_recall_curve(y_test, y_proba)

# Calcular F1 para cada umbral
f1_scores = 2 * (precision * recall) / (precision + recall)
best_threshold = thresholds[np.argmax(f1_scores)]

print(f"Mejor umbral para F1: {best_threshold:.3f}")

# Predecir con nuevo umbral
y_pred_new = (y_proba >= best_threshold).astype(int)

print("\n=== CON UMBRAL AJUSTADO ===")
print(classification_report(y_test, y_pred_new, target_names=['Legítimo', 'Fraude']))

📝 Entregables del Proyecto:

  1. Notebook de Jupyter con todas las fases documentadas.
  2. Gráficos: distribución inicial, matriz de confusión, curva ROC, curva Precisión-Exhaustividad.
  3. Tabla de comparación: métricas con umbral 0.5 vs. umbral óptimo.
  4. Conclusión escrita: ¿Qué tan bueno es el modelo? ¿Qué métrica priorizarías en producción y por qué? ¿Qué mejorarías en la próxima iteración?

💡 Notas Finales del Curso:

El preprocesamiento no es un mal necesario—es tu superpoder.
Nunca confíes en la precisión en problemas desbalanceados. Usa AUC-ROC, Exhaustividad, F1.
La validación cruzada estratificada es tu aliada para construir modelos robustos.
Documenta cada paso. Tu yo futuro (y tu equipo) te lo agradecerán.
En producción, monitorea no solo la precisión, sino la distribución de tus datos. ¡Puede cambiar con el tiempo!

Course Info

Course: AI-course1

Language: ES

Lesson: Module6