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.
- 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.
# 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
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.
| Concepto | Descripcion |
|---|---|
| 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". |
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
| Concepto | Descripcion |
|---|---|
| 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. |
# 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
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).
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)
M10Llevar 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.
# 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 Un proyecto “produccion-ready” tiene:
- Persistencia: joblib.dump(pipeline, ‘modelo.joblib’) guarda TODO (preprocessing + modelo). No pickles sueltos.
- API: FastAPI con validacion de input (Pydantic). Documentacion automatica en /docs.
- Monitoreo: loggear cada prediccion (input, output, latencia, version). Detectar drift: comparar distribucion de inputs vs train (KS test, PSI).
- Reentrenamiento: cron job semanal/mensual que reentrena con datos nuevos y reporta metricas. Si el AUC cae, alerta.
- 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
| Industria | Problema | Algoritmo tipico | Metrica 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
- Definir el problema: pregunta de negocio, KPI, metrica de exito, costo de FP/FN.
- EDA + limpieza: missing, outliers, transformaciones. Documentar todo.
- Feature engineering: Pipeline con ColumnTransformer, log, interacciones, encoding. Sin leakage.
- Baseline: DummyClassifier + Logistic Regression. Comparar contra ellos.
- 3+ modelos: con la misma metrica y mismo preprocesamiento. RF, GBM, KNN al menos.
- Tuning: Optuna o GridSearchCV en el mejor. Reportar cuanto mejoro el CV.
- Evaluacion final en test: UNA VEZ. Classification report + ROC-AUC + matriz de confusion.
- Explicabilidad: SHAP sobre el modelo final. Mostrar 3-5 predicciones explicadas.
- Reporte ejecutivo: 2-3 paginas en Markdown. Problema, datos, metodo, resultados, riesgos, proximos pasos.
- Repo + notebook ejecutable: README + requirements.txt + notebook de principio a fin sin errores.
10.8 Errores comunes
- Elige un dataset publico (sugerencia: House Prices, Titanic, Breast Cancer, Customer Churn de Kaggle). Define claramente la pregunta de negocio y la metrica principal.
- Hacé un EDA honesto: distribuciones, outliers, correlaciones, missing. Documenta 3 hipotesis en Markdown antes de empezar.
- Pipeline completo de feature engineering: imputacion + encoding + escalado + features nuevas (interacciones, log). Todo dentro del Pipeline.
- Prueba al menos 3 modelos (LR, RF, GBM) con la misma metrica y CV. Compara con un baseline (DummyClassifier).
- Tunea el ganador con Optuna o GridSearchCV. Reporta los mejores hiperparametros y cuanto mejoro el CV.
- Evalua en test UNA vez. Reporte completo: classification report, ROC-AUC, matriz de confusion, learning curves.
- Explicabilidad: SHAP sobre el modelo final. Mostrar 3-5 predicciones individuales explicadas.
- Guarda el pipeline con joblib. En un script aparte, cargalo y verifica reproducibilidad.
- Escribe un reporte ejecutivo de 2-3 paginas en Markdown. Seccion obligatoria: limitaciones y riesgos.
- Bonus: deploya con FastAPI en un endpoint POST. Probá con un caso real.
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.