D
Practica aplicada M6 intermedio 26 min

Capitulo 06

Machine Learning basico: el primer modelo de verdad

5 algoritmos, cuando usar cada uno, y por que el baseline es tu mejor amigo

Los 5 algoritmos fundamentales de ML (Logistic Regression, KNN, Arboles, Random Forest, Gradient Boosting), cuando usar cada uno, las metricas que importan segun el problema, y cross-validation para estimar performance real.

6.1 La verdad que nadie te dice en los tutoriales

En un proyecto de ML, el 80% del trabajo no es entrenar el modelo. Es: entender el problema, limpiar los datos, hacer feature engineering, validar honestamente, comunicar resultados. El modelo es el 20% que el negocio ve. Si los otros 80% estan mal, el modelo es ruido bonito.

Este modulo te da el vocabulario y la caja de herramientas de los 5 modelos que cubren el 95% de los problemas tabulares del mundo real.

6.2 Los 3 problemas canonicos de ML supervisado

ProblemaTargetMetricasEjemplo
bin y ∈ {0, 1} Spam/no-spam, fraude, churn.
multi y ∈ {0, 1, ..., K} Reconocer digitos, clasificar imagenes.
reg y ∈ ℝ Precio de casa, demanda, temperatura.
La pregunta que ordena todo

Antes de elegir modelo, responde: ¿Que error es mas caro, FP o FN? Esa respuesta determina la metrica, el threshold, y en ultima instancia el modelo. En medicina, FN (no detectar cancer) >> FP (falsa alarma). En spam, FP (marcar un mail bueno como spam) puede ser >> FN (dejar pasar un spam). En fraude, depende del volumen.

6.3 Los 5 algoritmos que tienes que dominar

Logistic Regression

M6

A pesar del nombre, es CLASIFICACION. Estima P(y=1|X) usando la funcion sigmoide. Lineal en los features (despues de transformacion). Pros: rapido, interpretable, da probabilidades bien calibradas. Contras: no captura relaciones no lineales.

Ej: Primer modelo que entrenar en cualquier problema de clasificacion. Si LR anda bien, los datos tienen estructura lineal. Si anda mal, considera features polinomiales o un modelo no lineal.

#ml #clasificacion #baseline

K-Nearest Neighbors (KNN)

M6

Clasifica un punto segun la mayoria de votos de sus K vecinos mas cercanos en el espacio de features. Lazy: no aprende nada en fit, todo el trabajo es en predict. Pros: simple, no asume distribucion. Contras: lento en prediccion con muchos datos, sensible al escalado y a features irrelevantes.

#ml #clasificacion #lazy

Arbol de Decision

M6

Particiona recursivamente el espacio de features usando preguntas binarias. Cada hoja tiene una prediccion. Pros: MUY interpretable (puedes ver el camino de decision), maneja mixto (numerico + categorico), no requiere escalado. Contras: overfittea con facilidad, inestable (pequenos cambios en datos cambian mucho el arbol).

#ml #clasificacion #interpretable

Random Forest

M6

Ensemble de muchos arboles de decision entrenados con (a) bootstrap samples de los datos y (b) subconjuntos aleatorios de features. Cada arbol vota. Pros: muy robusto, rara vez overfittea, no requiere escalado, da feature importance gratis. Contras: menos interpretable que un solo arbol, mas lento, modelos grandes.

#ml #ensemble #bagging

Gradient Boosting (XGBoost / LightGBM / CatBoost)

M6

Ensemble SECUENCIAL: cada arbol corrige los errores del anterior. Pros: estado del arte en datos tabulares, mayor accuracy que RF. Contras: mas hiperparametros, mas riesgo de overfit, mas lento de entrenar.

#ml #ensemble #boosting
Regla de eleccion (decision tree del senior)
  1. ¿Tienes > 10k muestras? Empieza con Logistic Regression. Es el baseline honesto.
  2. ¿La accuracy es inaceptable? KNN (datasets chicos) o Random Forest (datasets medianos).
  3. ¿Quieres el maximo de performance? Gradient Boosting con tuning.
  4. ¿Necesitas explicabilidad al negocio? Un solo Arbol de Decision o un modelo con SHAP sobre cualquier ensemble.

6.4 Comparativa head-to-head con datos reales

python Comparar 5 modelos con la misma metrica (codigo base)
import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score, StratifiedKFold
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.metrics import classification_report, roc_auc_score, f1_score

# Cargar datos
data = load_breast_cancer()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target  # 0=maligno, 1=benigno
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

# Modelos con la misma estructura de Pipeline
# - StandardScaler solo donde tiene sentido (LR y KNN)
# - Random_state fijo para reproducibilidad
modelos = {
    'Logistic Regression': Pipeline([
        ('scaler', StandardScaler()),
        ('model', LogisticRegression(max_iter=1000, random_state=42))
    ]),
    'KNN (k=5)': Pipeline([
        ('scaler', StandardScaler()),
        ('model', KNeighborsClassifier(n_neighbors=5))
    ]),
    'Decision Tree': Pipeline([
        ('model', DecisionTreeClassifier(max_depth=5, random_state=42))
    ]),
    'Random Forest': Pipeline([
        ('model', RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42, n_jobs=-1))
    ]),
    'Gradient Boosting': Pipeline([
        ('model', GradientBoostingClassifier(n_estimators=100, max_depth=3, random_state=42))
    ]),
}

# Validacion cruzada ESTRATIFICADA (mantiene proporcion de clases)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
print(f"{'Modelo':<22} {'Accuracy':<12} {'F1':<10} {'ROC-AUC':<10}")
print("=" * 60)

for nombre, modelo in modelos.items():
    acc = cross_val_score(modelo, X_train, y_train, cv=cv, scoring='accuracy').mean()
    f1  = cross_val_score(modelo, X_train, y_train, cv=cv, scoring='f1').mean()
    auc = cross_val_score(modelo, X_train, y_train, cv=cv, scoring='roc_auc').mean()
    print(f"{nombre:<22} {acc:.3f}        {f1:.3f}     {auc:.3f}")

# NOTA: se entrena 5 modelos * 3 metricas * 5 folds = 75 fits por ejecucion
# En datasets grandes, considera usar n_jobs=-1

6.5 Cross-Validation: la verdad sobre tu modelo

K-Fold Cross-Validation

M6

Divide los datos en K partes. Entrena K veces, cada vez usando K-1 partes para entrenar y 1 para validar. La metrica final es la MEDIA de las K metricas. Ventaja: usa todos los datos para train y test, da estimacion de varianza (std entre folds).

#ml #validacion #core
Regla fundamental del CV

Todo el preprocessing (imputacion, escalado, encoding, feature selection) va ADENTRO del loop de CV. Si lo haces ANTES del CV, la informacion del fold de validacion se filtra al train via las estadisticas globales. Ejemplo clasico: imputar con la media de TODO el dataset antes del CV = leakage.

python K-Fold sin leakage (forma correcta)
from sklearn.model_selection import cross_val_score, KFold
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

# FORMA INCORRECTA (leakage)
# imp = SimpleImputer()
# X_imp = imp.fit_transform(X)  # usa la media de TODO el dataset
# cross_val_score(model, X_imp, y)  # cada fold usa stats de test

# FORMA CORRECTA (sin leakage)
model = Pipeline([
    ('imputer', SimpleImputer()),  # aprende la media SOLO en train de cada fold
    ('scaler',   StandardScaler()),
    ('clf',      LogisticRegression())
])

cv = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=cv, scoring='roc_auc')
print(f"AUC: {scores.mean():.3f} ± {scores.std():.3f}")
Variantes de K-Fold que necesitas conocer
  • Stratified K-Fold: mantiene la proporcion de clases en cada fold. Es el default para clasificacion desbalanceada.
  • TimeSeriesSplit: para series temporales. Train en [0:t], val en [t:t+k], desplazandose. Nunca mira el futuro.
  • Group K-Fold: cuando hay grupos (ej: mismo paciente en multiples filas). No separa filas del mismo grupo entre train y val.
  • Leave-One-Out: K=N. Cada fold es 1 muestra. Solo util con datasets muy pequenos (< 100).

6.6 Bias-Variance tradeoff (el diagnostico fundamental)

Dos formas de fallar
  • Bias alto (underfitting): el modelo es demasiado simple, no captura la estructura real de los datos. Error alto en train Y en test. Solucion: modelo mas complejo, mejores features, menos regularizacion.
  • Variance alta (overfitting): el modelo es demasiado complejo, memoriza ruido del train. Error bajo en train, alto en test. Solucion: mas datos, regularizacion (max_depth menor, alpha mayor, dropout), ensemble.

El objetivo: encontrar el punto de equilibrio, generalmente via learning curves.

python Learning curves: el diagnostico definitivo
import matplotlib.pyplot as plt
import numpy as np
from sklearn.model_selection import learning_curve
from sklearn.ensemble import RandomForestClassifier

train_sizes, train_scores, val_scores = learning_curve(
    RandomForestClassifier(n_estimators=100, max_depth=10, random_state=42),
    X_train, y_train,
    cv=5,
    train_sizes=np.linspace(0.1, 1.0, 10),
    scoring='roc_auc',
    n_jobs=-1,
)

train_mean = train_scores.mean(axis=1)
val_mean   = val_scores.mean(axis=1)

plt.figure(figsize=(8, 5))
plt.plot(train_sizes, train_mean, 'o-', label='Train AUC', color='#06B6D4')
plt.plot(train_sizes, val_mean, 'o-', label='Validation AUC', color='#8B5CF6')
plt.fill_between(train_sizes, val_mean - val_scores.std(axis=1), val_mean + val_scores.std(axis=1), alpha=0.2, color='#8B5CF6')
plt.xlabel('Tamanio del training set')
plt.ylabel('ROC-AUC')
plt.title('Learning Curves: diagnostico de bias-variance')
plt.legend()
plt.grid(alpha=0.3)
import seaborn as sns; sns.despine()
plt.tight_layout()
plt.show()

# Diagnostico:
# - Train alto, val bajo, curvas NO convergen → overfitting. Mas datos o regularizacion.
# - Train bajo, val bajo, curvas convergen → underfitting. Modelo mas complejo.
# - Train alto, val alto, curvas convergen → punto optimo.

6.7 Errores comunes

Usar accuracy en clases desbalanceadas
✗ Dataset 99% clase 0, 1% clase 1. Modelo predice siempre 0 → 99% accuracy. Pero no detecta nigun fraude.
✓ F1-Score, ROC-AUC, PR-AUC (mejor en desbalance extremo). Ajusta el threshold por costo de negocio.
No comparar contra un baseline tonto
✗ Random Forest con 0.85 accuracy. Wow! Pero nunca comparaste con la clase mayoritaria.
✓ Siempre: DummyClassifier(strategy='most_frequent') o 'stratified'. Si tu modelo no los supera, no sirve.
Mirar el test set para tomar decisiones
✗ Pruebo LR, RF, GBM. Reporto el AUC en test del que dio mejor. Pero ya gaste mi test.
✓ El test set se mira UNA vez al final. Toda seleccion de modelo e hiperparametros va con CV en train.
Estandarizar antes del train_test_split (data leakage)
✗ X_scaled = StandardScaler().fit_transform(X); train_test_split(X_scaled, y)
✓ Estandarizar DENTRO del Pipeline: pipeline.fit(X_train); pipeline.predict(X_test). El scaler aprende solo de train.
Reporte solo accuracy en el test final
✗ 'Mi modelo da 90% accuracy'. Listo.
✓ Reporte el classification_report completo: precision, recall, F1 POR CLASE. La accuracy esconde errores en clases minoritarias.
Libro: "An Introduction to Statistical Learning" (ISLR) - James, Witten, Hastie, Tibshirani. Cap 2, 3, 4, 8 son el canon. Gratuito online.
Libro: "Hands-On Machine Learning" (3ra ed) - Aurélien Géron. Cap 1-4 intro, cap 6-7 algoritmos.
Video: StatQuest: "Machine Learning" (YouTube, ~10 videos, explica desde cero)
Video: Andrew Ng: "Machine Learning Specialization" (Coursera, gratis para revisar, el canon historico)
Articulo: "A Few Useful Things to Know About Machine Learning" - Pedro Domingos (2012, ens clasico)
Herramienta: scikit-learn: la libreria canon para ML clasico en Python
Herramienta: XGBoost / LightGBM / CatBoost: gradient boosting optimizado para produccion
Mini-proyecto 6: comparativa de 5 modelos con honestidad intermedio
  1. Cargá un dataset publico de clasificacion (Titanic, Breast Cancer, Iris, Wine). Documenta el problema en 3 lineas.
  2. Establece UNA metrica principal segun el tipo de problema (F1, ROC-AUC, etc). Justifica tu eleccion.
  3. Entrena los 5 modelos (LR, KNN, DT, RF, GBM) usando Pipeline + StandardScaler + Cross-Validation con Stratified K-Fold (k=5). Reporta media y std de la metrica en CV.
  4. Para el modelo ganador, hace un reporte completo en el test set: classification report + ROC-AUC + matriz de confusion. Comenta que clase es mas dificil de predecir y por que.
  5. Calcula el baseline con DummyClassifier(strategy=‘most_frequent’). Si tu modelo no lo supera por un margen significativo, el problema no justifica ML.
  6. Bonus: ajusta hiperparametros del mejor modelo con GridSearchCV. Reporta los mejores hiperparametros y cuanto mejoro el CV.