Por qué explicabilidad y tracking son ya parte del flujo de Scikit-learn
Una vez entrenado un modelo, cualquier equipo profesional necesita responder a dos preguntas que la métrica global (accuracy, ROC-AUC) no resuelve:
- ¿Por qué el modelo ha predicho eso para este caso concreto? (explicabilidad)
- ¿Qué versión, con qué datos y qué hiperparámetros produjo este rendimiento? (trazabilidad)
En este módulo cubrimos las dos con las herramientas estándar del ecosistema: SHAP (SHapley Additive exPlanations) para explicabilidad de cualquier modelo y MLflow para registrar y comparar experimentos. Ambas se integran de forma natural con la API de Scikit-learn.
flowchart LR
DATA[Dataset] --> PIPE[Pipeline sklearn]
PIPE --> EVAL["cross_val_score,\nmétricas sklearn.metrics"]
PIPE --> EXPL[SHAP]
PIPE --> TRACK[MLflow]
EXPL --> LOCAL["Explicación local\nwaterfall plot"]
EXPL --> GLOBAL["Explicación global\nsummary plot"]
TRACK --> PARAMS["params, metrics,\nartifacts"]
TRACK --> REG["Model Registry\nstage: staging/production"]
REG --> SERVE["mlflow models serve\nendpoint HTTP"]
Valores SHAP en un modelo de Scikit-learn
SHAP asigna a cada feature una contribución numérica a la predicción concreta de una observación. La suma de todas las contribuciones más un valor base reproduce exactamente la salida del modelo. Esto permite explicaciones locales (por qué se predijo esta fila) y globales (qué features importan en todo el dataset).
Para modelos basados en árboles (RandomForest, HistGradientBoosting, XGBoost, LightGBM, CatBoost) SHAP ofrece un TreeExplainer muy rápido; para el resto usa KernelExplainer o PermutationExplainer.
import shap
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_openml
X, y = fetch_openml("adult", version=2, as_frame=True, return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X.select_dtypes("number").fillna(0),
(y == ">50K").astype(int),
random_state=42,
)
modelo = HistGradientBoostingClassifier(max_iter=200, random_state=42)
modelo.fit(X_train, y_train)
explainer = shap.TreeExplainer(modelo)
shap_values = explainer(X_test.iloc[:200])
# Explicación global: importancia agregada
shap.summary_plot(shap_values, X_test.iloc[:200])
# Explicación local: una fila concreta
shap.plots.waterfall(shap_values[0])
El summary_plot muestra para cada feature cómo su valor empuja la predicción hacia arriba o hacia abajo: en un problema de clasificación binaria, los puntos rojos indican valores altos de la feature y los azules, valores bajos. Es la visualización estándar para reportar un modelo a stakeholders no técnicos.
SHAP con un Pipeline
Cuando el modelo vive dentro de un Pipeline, SHAP se aplica sobre el estimador final usando los datos ya transformados. Un patrón seguro es transformar manualmente y después explicar:
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from xgboost import XGBClassifier
preproc = ColumnTransformer(transformers=[
("num", StandardScaler(), num_cols),
("cat", OneHotEncoder(handle_unknown="ignore"), cat_cols),
])
pipe = Pipeline(steps=[
("preproc", preproc),
("modelo", XGBClassifier(eval_metric="logloss")),
])
pipe.fit(X_train, y_train)
# Datos ya transformados para SHAP
X_test_trans = pipe.named_steps["preproc"].transform(X_test)
feature_names = pipe.named_steps["preproc"].get_feature_names_out()
explainer = shap.TreeExplainer(pipe.named_steps["modelo"])
shap_values = explainer(X_test_trans)
shap.summary_plot(shap_values, X_test_trans, feature_names=feature_names)
El método get_feature_names_out() del ColumnTransformer devuelve los nombres tras la transformación (incluyendo sufijos de OneHotEncoder), y SHAP los usa para etiquetar los gráficos. Combinado con set_output(transform="pandas") este flujo resulta especialmente claro.
MLflow: tracking de experimentos con autolog
MLflow registra automáticamente parámetros, métricas y artefactos de un entrenamiento mediante mlflow.sklearn.autolog(). A partir de ese punto, cualquier llamada a fit dentro de un mlflow.start_run() queda trazada, incluyendo el modelo serializado como artefacto y los gráficos de importancia.
import mlflow
import mlflow.sklearn
from sklearn.ensemble import HistGradientBoostingClassifier
mlflow.set_experiment("scikit-learn-adult")
mlflow.sklearn.autolog()
with mlflow.start_run(run_name="hgb-baseline"):
modelo = HistGradientBoostingClassifier(max_iter=200, learning_rate=0.05)
modelo.fit(X_train, y_train)
score = modelo.score(X_test, y_test)
mlflow.log_metric("accuracy_test", score)
Al ejecutar mlflow ui en la terminal, se abre un panel web en http://localhost:5000 donde comparar runs, ordenarlos por métricas y visualizar gráficos. Este panel reemplaza al viejo patrón de mantener tablas manuales con resultados de experimentos.
Registry y despliegue con mlflow models serve
El Model Registry de MLflow permite registrar un modelo y asignarle un nombre y una etapa (staging, production). Una vez registrado, cualquier servicio puede cargarlo por nombre sin depender de rutas de disco.
# Registrar el modelo asociado al run actual
with mlflow.start_run(run_name="hgb-registry") as run:
modelo.fit(X_train, y_train)
mlflow.sklearn.log_model(
sk_model=modelo,
artifact_path="modelo",
registered_model_name="hgb-adult",
)
Para servirlo como endpoint HTTP en desarrollo:
mlflow models serve -m "models:/hgb-adult/Production" -p 5001 --no-conda
El servidor expone POST /invocations aceptando JSON con el esquema {"dataframe_split": {...}} o {"instances": [...]} y devuelve predicciones. Así puedes probar el modelo en producción antes de empaquetarlo en una imagen Docker o desplegarlo en un servicio gestionado.
Integración con el curso
Este flujo cierra el curso cubriendo la vida completa del modelo:
- Preprocesado + modelado con
PipelineyColumnTransformer(módulos 2 y 9). - Evaluación y ajuste con métricas y
HalvingRandomSearchCV(módulo 8). - Explicabilidad con SHAP para justificar decisiones del modelo.
- Tracking y despliegue con MLflow para garantizar reproducibilidad.
Con estas cuatro capas tu proyecto de Scikit-learn está listo para pasar de notebook a producción de forma sostenible.
Caso B2B: auditoría regulatoria de un modelo de scoring crediticio
Una entidad financiera desarrolla un modelo de scoring para decisiones de concesión de crédito al consumo. El regulador exige trazabilidad completa (qué datos entrenaron el modelo, qué hiperparámetros se usaron) y explicabilidad individual (por qué se rechazó a un solicitante concreto). SHAP + MLflow cubren ambas exigencias sin herramientas adicionales.
import mlflow
import mlflow.sklearn
import shap
import pandas as pd
from lightgbm import LGBMClassifier
from sklearn.model_selection import train_test_split, cross_val_score
mlflow.set_experiment("scoring-credito-prod")
mlflow.sklearn.autolog()
df = pd.read_parquet("solicitudes_credito.parquet", dtype_backend="pyarrow")
X = df.drop(columns=["impago_12m"])
y = df["impago_12m"].astype(int)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42,
)
with mlflow.start_run(run_name="lgbm-v3-regulador") as run:
modelo = LGBMClassifier(
n_estimators=400,
learning_rate=0.05,
num_leaves=31,
class_weight="balanced",
random_state=42,
)
modelo.fit(X_train, y_train)
# Metricas registradas automaticamente por autolog + manual log
auc_cv = cross_val_score(modelo, X_train, y_train, cv=5, scoring="roc_auc").mean()
mlflow.log_metric("roc_auc_cv", auc_cv)
# Explicabilidad global con SHAP
explainer = shap.TreeExplainer(modelo)
shap_values = explainer(X_test.iloc[:500])
shap.summary_plot(shap_values, X_test.iloc[:500], show=False)
mlflow.log_figure(plt.gcf(), "shap_summary.png")
# Explicabilidad local: justificacion por solicitud
for idx_solicitud in [7, 42, 189]:
shap.plots.waterfall(shap_values[idx_solicitud], show=False)
mlflow.log_figure(plt.gcf(), f"shap_waterfall_{idx_solicitud}.png")
Al finalizar la ejecución, el run en MLflow contiene:
- Hiperparámetros del modelo (registrados por
autolog). - Métricas de entrenamiento y validación cruzada.
- Artefacto serializado del modelo (reproducible via
mlflow.sklearn.load_model). - Gráficos SHAP globales y locales adjuntos al run.
El equipo de compliance accede al panel de MLflow, descarga el informe de cualquier decisión rechazada y obtiene la lista de features con su contribución numérica. Este flujo cubre la exigencia del artículo 22 del RGPD sobre decisiones automatizadas y deja rastro de auditoría completo sin salir del ecosistema Scikit-learn.
Patrón de servicio: modelo + explicabilidad en FastAPI
Una vez registrado el modelo, un microservicio FastAPI carga la versión de producción desde el Model Registry y devuelve tanto la predicción como la explicación SHAP para cada solicitud:
from fastapi import FastAPI
from pydantic import BaseModel
import mlflow.sklearn
import shap
import numpy as np
app = FastAPI(title="Scoring credito explicable")
modelo = mlflow.sklearn.load_model("models:/scoring-credito/Production")
explainer = shap.TreeExplainer(modelo)
class Solicitud(BaseModel):
ingresos: float
deuda: float
antiguedad_laboral: float
gasto_mensual: float
@app.post("/score")
async def score(datos: Solicitud) -> dict:
features = np.array([[datos.ingresos, datos.deuda,
datos.antiguedad_laboral, datos.gasto_mensual]])
proba = modelo.predict_proba(features)[0][1]
shap_vals = explainer(features).values[0]
contribuciones = dict(zip(
["ingresos", "deuda", "antiguedad", "gasto"],
[round(float(v), 4) for v in shap_vals],
))
return {
"probabilidad_impago": round(float(proba), 4),
"contribuciones_shap": contribuciones,
}
Cada respuesta lleva la justificación individual: el cliente rechazado puede recibir una explicación concreta ("su ratio deuda/ingresos aporta +0.32 a la probabilidad de impago"), y el equipo de soporte dispone de información accionable para recomendar productos alternativos o mejoras en el perfil del solicitante.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Scikit Learn es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Scikit Learn
Explora más contenido relacionado con Scikit Learn y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Calcular e interpretar valores SHAP para modelos de Scikit-learn y de boosting. Generar gráficos summary, waterfall y dependence para explicar predicciones individuales y globales. Registrar parámetros, métricas y artefactos en MLflow con autolog. Cargar y servir modelos registrados con mlflow models serve.