D
Maestria M10 avanzado 35 min

Capitulo 10

Fundamentos de IA, Machine Learning y Produccion

El modulo integrador: de Python a pipelines de ML en produccion

El cierre de la cursada: el mapa completo de la IA (ML, DL, IA Generativa, RL), feature engineering avanzado, validacion con GridSearch y Optuna, reproducibilidad profesional, despliegue minimo viable con FastAPI y casos de uso por industria.

10.1 El mapa completo: IA, ML, Deep Learning, Generativa

Antes de seguir, ordenemos las cosas. “IA” es el campo amplio, “Machine Learning” es un subcampo, “Deep Learning” es un subcampo de ML, y “IA Generativa” es un tipo de modelo que cruza varios campos. Confundirlos es la primera causa de respuestas vagas en entrevistas.

Jerarquia conceptual
  • Inteligencia Artificial (IA): cualquier sistema que simula inteligencia. Subcampos: ML, NLP, Computer Vision, Robotica, Planificacion.
  • Machine Learning (ML): subcampo de la IA donde los sistemas APRENDEN desde datos sin estar programados explicitamente. Tipos: supervisado, no supervisado, por refuerzo.
  • Deep Learning (DL): subcampo de ML que usa redes neuronales con muchas capas. Estado del arte en imagenes, texto, audio, video.
  • IA Generativa: modelos que CREAN contenido nuevo (texto, imagenes, codigo, audio). Ej: GPT-4, DALL-E, Stable Diffusion, Midjourney, Claude, Gemini.
  • LLM (Large Language Model): modelo de lenguaje entrenado con miles de millones de parametros sobre corpus de texto. Base de la IA generativa de texto.
python Pregunta de entrevista: define la jerarquia
# En entrevista, demuestra que entiendes la jerarquia con EJEMPLOS concretos.
#
# IA:           Cualquier sistema inteligente.
#               - Ej: un termostato con reglas if-else (clasico "symbolic AI")
#
# ML:           Sistemas que aprenden de datos.
#               - Ej: un modelo de prediccion de churn
#
# DL:           Redes neuronales profundas (> 5 capas tipicamente).
#               - Ej: una CNN que clasifica imagenes de radiografias
#
# Generativa:   Crea contenido nuevo.
#               - Ej: Stable Diffusion genera imagenes a partir de texto
#
# LLM:          Modelo de lenguaje grande.
#               - Ej: GPT-4, Claude 3, Gemini, LLaMA 3

10.2 Feature engineering: donde se gana la partida

La regla del 80/20 del ML

En la mayoria de proyectos, el 80% de la ganancia en performance viene de mejores features, no de modelos mas complejos. Un Random Forest con features bien construidas le gana a una red neuronal profunda con features crudas.

ConceptoDescripcion
log Para distribuciones sesgadas (ingresos, visitas). Reduce la cola larga. Comun en econometria y ML.
bin Convertir continuo en rangos (ej: 0-18, 18-30, 30-50, 50+). Util cuando la relacion no es monotona.
ohe Una columna binaria (0/1) por categoria. Simple pero ineficiente para alta cardinalidad (categoria con 10k valores).
te Reemplaza cada categoria con la MEDIA del target. Util con alta cardinalidad. ⚠️ Riesgo de leakage: hacer con CV.
freq Reemplaza cada categoria con su FRECUENCIA. Sin leakage. Captura "popularidad" como feature.
int Producto, ratio, suma entre features. Captura efectos conjuntos. Ej: precio_metro_cuadrado = precio / superficie.
time Dia de la semana, mes, "es fin de semana", "es feriado", "dias hasta el proximo feriado".
agg Promedio, count, ratio, std por grupo. "Ticket medio por categoria" > "ticket individual".
python Custom transformer que encaja en un Pipeline
import numpy as np
import pandas as pd
from sklearn.base import BaseEstimator, TransformerMixin

class InteractionFeatures(BaseEstimator, TransformerMixin):
    """Crea features de interaccion entre columnas. Encaja en un Pipeline."""

    def __init__(self, interaction_cols=None):
        self.interaction_cols = interaction_cols

    def fit(self, X, y=None):
        return self  # no aprende nada

    def transform(self, X):
        X = pd.DataFrame(X, columns=self.interaction_cols) if isinstance(X, np.ndarray) else X.copy()
        cols = self.interaction_cols or X.columns.tolist()
        for i, c1 in enumerate(cols):
            for c2 in cols[i+1:]:
                X[f'{c1}_x_{c2}'] = X[c1] * X[c2]
        return X

class LogTransformer(BaseEstimator, TransformerMixin):
    """Aplica np.log1p a columnas especificas."""

    def __init__(self, cols=None):
        self.cols = cols

    def fit(self, X, y=None):
        return self

    def transform(self, X):
        X = X.copy()
        for c in self.cols:
            X[c] = np.log1p(X[c])
        return X

# Uso en un Pipeline:
# from sklearn.pipeline import Pipeline
# pipe = Pipeline([
#     ('log',     LogTransformer(cols=['tarifa', 'precio'])),
#     ('scaler',  StandardScaler()),
#     ('inter',   InteractionFeatures(interaction_cols=['edad', 'ingreso'])),
#     ('model',   RandomForestClassifier())
# ])

10.3 Validacion: GridSearchCV, RandomizedSearchCV, Optuna

ConceptoDescripcion
Grid Prueba TODAS las combinaciones de un grid. Exhaustive. Costoso: O(n_combinaciones * cv_folds). Util cuando el espacio es chico (< 50 combinaciones).
Random Muestrea N combinaciones al azar. Mas eficiente que Grid para espacios grandes. Recomendado como default.
Optuna Busqueda BAYESIANA. Aprende de iteraciones anteriores y enfoca el presupuesto en zonas prometedoras. 10-100x mas eficiente que Random.
Halving Asignacion sucesiva: prueba todas las combinaciones con pocos recursos, las Mejores se prueban con mas.
python Optuna: busqueda bayesiana con early stopping
# pip install optuna
import optuna
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

data = load_breast_cancer()
X, y = data.data, data.target

def objetivo(trial):
    """Funcion que Optuna minimiza (o maximiza con direction='maximize')."""
    params = {
        'n_estimators':      trial.suggest_int('n_estimators', 50, 500),
        'max_depth':         trial.suggest_int('max_depth', 3, 20),
        'min_samples_leaf':  trial.suggest_int('min_samples_leaf', 1, 50),
        'max_features':      trial.suggest_categorical('max_features', ['sqrt', 'log2', None]),
    }
    pipe = Pipeline([
        ('scaler', StandardScaler()),
        ('model', RandomForestClassifier(**params, random_state=42, n_jobs=-1))
    ])
    cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
    return cross_val_score(pipe, X, y, cv=cv, scoring='roc_auc', n_jobs=-1).mean()

# Crear estudio con early stopping
study = optuna.create_study(
    direction='maximize',
    pruner=optuna.pruners.MedianPruner()  # corta trials que van mal
)
study.optimize(
    objetivo,
    n_trials=50,           # maximo de trials
    timeout=300,           # o 5 minutos, lo que llegue primero
    show_progress_bar=False
)

print(f"Mejor AUC: {study.best_value:.4f}")
print(f"Mejores hiperparametros: {study.best_params}")
print(f"Trials completados: {len(study.trials)}")

10.4 Reproducibilidad: la diferencia entre un proyecto y un experimento

Sin reproducibilidad, no hay ciencia

Si corres el mismo codigo dos veces y da resultados distintos, tu proyecto es fragil. La reproducibilidad se logra con: (1) random_state en TODO (numpy, sklearn, model.fit), (2) requirements.txt con versiones exactas, (3) entorno virtual, (4) datos versionados (DVC o al menos en S3 con hashes), (5) notebooks ejecutables de principio a fin (Kernel → Restart & Run All).

python Setup reproducible: el patron obligatorio
import os
import random
import numpy as np
import torch  # si usas deep learning
import tensorflow as tf  # si usas TF

# 1) PYTHONHASHSEED (importante para dicts, sets)
os.environ['PYTHONHASHSEED'] = '42'

# 2) Python random
random.seed(42)

# 3) NumPy
np.random.seed(42)

# 4) PyTorch
torch.manual_seed(42)
torch.cuda.manual_seed_all(42)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False

# 5) TensorFlow
tf.random.set_seed(42)

# 6) En sklearn: random_state=42 en TODOS los modelos y splits

# 7) requirements.txt
# numpy==1.24.3
# pandas==2.0.1
# scikit-learn==1.3.0
# matplotlib==3.7.1
# seaborn==0.12.2

# 8) Antes de entregar: Kernel → Restart & Run All
# Si falla, tienes un bug de orden de ejecucion.

10.5 Despliegue minimo viable: del notebook a la API

MLOps (nivel junior)

M10

Llevar un modelo del notebook a produccion de forma REPRODUCIBLE, ROBUSTA y OBSERVABLE. Minimo viable: Pipeline persistido con joblib + API con FastAPI + monitoreo de drift + plan de reentrenamiento. No requiere Kubernetes.

#mlops #produccion #core
python API minima con FastAPI para servir un modelo
# pip install fastapi uvicorn
# main.py
from fastapi import FastAPI
from pydantic import BaseModel, Field
import joblib
import numpy as np

app = FastAPI(title="DSBook Churn API", version="1.0.0")
model_data = joblib.load('churn_pipeline.joblib')
pipeline = model_data['pipeline']
metadata = model_data.get('metadata', {})

class Cliente(BaseModel):
    """Schema de entrada: valida automaticamente con Pydantic."""
    tenure:           int   = Field(..., ge=0, le=100, description="Meses como cliente")
    monthly_charges:  float = Field(..., ge=0)
    total_charges:    float = Field(..., ge=0)
    contract:         str   = Field(..., pattern="^(Mes a mes|1 anio|2 anios)$")
    internet:         str   = Field(..., pattern="^(Fibra|DSL|No)$")
    tech_support:     str   = Field(None, pattern="^(Si|No)$")

class Prediccion(BaseModel):
    probabilidad_churn: float
    prediccion:         str
    modelo:             str
    umbral:             float = 0.5

@app.get("/")
def root():
    return {
        "modelo":   metadata.get('modelo', 'desconocido'),
        "version":  app.version,
        "auc_test": metadata.get('auc_test'),
    }

@app.post("/predecir", response_model=Prediccion)
def predecir(cliente: Cliente):
    X = np.array([[
        cliente.tenure, cliente.monthly_charges, cliente.total_charges,
        cliente.contract, cliente.internet, cliente.tech_support
    ]], dtype=object)
    prueba = pipeline.predict_proba(X)[0, 1]
    return Prediccion(
        probabilidad_churn=float(prueba),
        prediccion="churn" if prueba >= 0.5 else "activo",
        modelo=metadata.get('modelo', 'churn_v1'),
    )

# Correr: uvicorn main:app --reload
# Documentacion automatica: http://localhost:8000/docs
El MLOps minimo viable

Un proyecto “produccion-ready” tiene:

  1. Persistencia: joblib.dump(pipeline, ‘modelo.joblib’) guarda TODO (preprocessing + modelo). No pickles sueltos.
  2. API: FastAPI con validacion de input (Pydantic). Documentacion automatica en /docs.
  3. Monitoreo: loggear cada prediccion (input, output, latencia, version). Detectar drift: comparar distribucion de inputs vs train (KS test, PSI).
  4. Reentrenamiento: cron job semanal/mensual que reentrena con datos nuevos y reporta metricas. Si el AUC cae, alerta.
  5. Explicabilidad: SHAP para explicar predicciones individuales a stakeholders o regulators.

No requiere Kubernetes al principio. Un solo VPS, un cron, y disciplina.

10.6 Casos de uso por industria

IndustriaProblemaAlgoritmo tipicoMetrica principal
Salud Diagnostico (cancer, retinopatia) Recall (no dejar pasar un caso)
Finanzas Deteccion de fraude Recall @ threshold bajo (costo del FP bajo)
Retail Recomendacion + segmentacion RFM Precision@K + uplift de campana
Marketing Churn prediction + uplift modeling F1 + ROI de campana
Industria Mantenimiento predictivo Recall (no perder una falla)
NLP Sentimiento, clasificacion, chatbots F1, exactitud de intencion
Vision Deteccion de objetos, OCR mAP (mean Average Precision)

10.7 El proyecto capstone

El proyecto que demuestra que sabes hacer ML
  1. Definir el problema: pregunta de negocio, KPI, metrica de exito, costo de FP/FN.
  2. EDA + limpieza: missing, outliers, transformaciones. Documentar todo.
  3. Feature engineering: Pipeline con ColumnTransformer, log, interacciones, encoding. Sin leakage.
  4. Baseline: DummyClassifier + Logistic Regression. Comparar contra ellos.
  5. 3+ modelos: con la misma metrica y mismo preprocesamiento. RF, GBM, KNN al menos.
  6. Tuning: Optuna o GridSearchCV en el mejor. Reportar cuanto mejoro el CV.
  7. Evaluacion final en test: UNA VEZ. Classification report + ROC-AUC + matriz de confusion.
  8. Explicabilidad: SHAP sobre el modelo final. Mostrar 3-5 predicciones explicadas.
  9. Reporte ejecutivo: 2-3 paginas en Markdown. Problema, datos, metodo, resultados, riesgos, proximos pasos.
  10. Repo + notebook ejecutable: README + requirements.txt + notebook de principio a fin sin errores.

10.8 Errores comunes

No fijar la semilla aleatoria en todo el codigo
✗ Resultados distintos cada vez que corro el notebook
✓ np.random.seed(42), random_state=42 en todos los modelos y splits
Feature engineering antes del train/test split
✗ Calcular 'media por categoria' usando todo el dataset, despues splitear
✓ Split primero, luego todo el FE dentro de un Pipeline ajustado solo en train
Persistir solo el modelo, no el pipeline
✗ joblib.dump(modelo) # en produccion faltan scaler, imputer, encoder
✓ joblib.dump(pipeline_completo) # preprocessing + modelo juntos
Sin requirements.txt o sin versiones fijadas
✗ 'En mi maquina funciona con pandas 2.0' pero el server tiene 1.5
✓ pip freeze > requirements.txt # todas las versiones exactas
Asumir que mas features = mejor modelo
✗ Tirar 200 features al modelo y esperar que mejore
✓ Seleccion de features (SelectKBest, L1) o feature importance de arbol
Libro: "Designing Machine Learning Systems" - Chip Huyen. EL libro de MLOps. Cap 1-4 sobre el ciclo de vida de un sistema ML.
Libro: "Hands-On Machine Learning" (3ra ed) - Aurélien Géron. Cap 2 cubre end-to-end projects.
Paper: Sculley et al: "Hidden Technical Debt in Machine Learning Systems" (NeurIPS 2015, lectura obligatoria sobre el costo real del ML)
Video: Andrew Ng: "AI for Everyone" + "Machine Learning Engineering for Production" (Coursera)
Video: StatQuest: todo el canal (explica ML desde cero con visualizaciones)
Articulo: "Rules of Machine Learning" - Google (best practices de Martin Zinkevich)
Herramienta: MLflow: tracking de experimentos, model registry, deployment
Herramienta: DVC: data version control, versionar datasets y modelos como codigo
Herramienta: Optuna: hyperparameter tuning con busqueda bayesiana
Herramienta: SHAP: explicabilidad de modelos, basada en teoria de juegos
Mini-proyecto 10: el capstone definitivo avanzado
  1. Elige un dataset publico (sugerencia: House Prices, Titanic, Breast Cancer, Customer Churn de Kaggle). Define claramente la pregunta de negocio y la metrica principal.
  2. Hacé un EDA honesto: distribuciones, outliers, correlaciones, missing. Documenta 3 hipotesis en Markdown antes de empezar.
  3. Pipeline completo de feature engineering: imputacion + encoding + escalado + features nuevas (interacciones, log). Todo dentro del Pipeline.
  4. Prueba al menos 3 modelos (LR, RF, GBM) con la misma metrica y CV. Compara con un baseline (DummyClassifier).
  5. Tunea el ganador con Optuna o GridSearchCV. Reporta los mejores hiperparametros y cuanto mejoro el CV.
  6. Evalua en test UNA vez. Reporte completo: classification report, ROC-AUC, matriz de confusion, learning curves.
  7. Explicabilidad: SHAP sobre el modelo final. Mostrar 3-5 predicciones individuales explicadas.
  8. Guarda el pipeline con joblib. En un script aparte, cargalo y verifica reproducibilidad.
  9. Escribe un reporte ejecutivo de 2-3 paginas en Markdown. Seccion obligatoria: limitaciones y riesgos.
  10. Bonus: deploya con FastAPI en un endpoint POST. Probá con un caso real.
Para cerrar

Esta guia de estudio fue una foto de un momento. El campo del ML cambia semanalmente. Lo que importa no es la foto, es la capacidad de seguir actualizandote solo: leer papers, hacer proyectos, recibir feedback, iterar. Si llegaste hasta aca, ya tienes las herramientas. El resto es practica.