tutoriales.com

Explicabilidad en Machine Learning: Interpreta tus Modelos con SHAP y LIME en Python

Este tutorial te sumerge en el fascinante mundo de la explicabilidad de modelos de Machine Learning (XAI). Descubre cómo SHAP y LIME te permiten entender por qué un modelo tomó una decisión específica y la importancia global de sus características. Aprenderás a implementar estas técnicas en Python para construir modelos más transparentes y confiables.

Intermedio18 min de lectura29 views
Reportar error

La explicabilidad en Machine Learning (XAI) se ha convertido en una necesidad imperante, especialmente en dominios donde la transparencia y la confianza son cruciales, como la medicina, las finanzas o la justicia. Ya no basta con tener modelos con alta precisión; necesitamos entender cómo llegan a sus conclusiones. ¿Por qué un modelo predijo que un cliente es de alto riesgo? ¿Qué características fueron las más influyentes en una clasificación de cáncer?

Este tutorial abordará dos de las técnicas más populares y efectivas para la explicabilidad de modelos: SHAP (SHapley Additive exPlanations) y LIME (Local Interpretable Model-agnostic Explanations). Ambas nos permiten obtener insights valiosos, tanto a nivel global (cómo funciona el modelo en general) como a nivel local (por qué se hizo una predicción específica).


🎯 ¿Por qué es importante la explicabilidad?

En un mundo donde los modelos de Machine Learning influyen cada vez más en decisiones críticas, la explicabilidad es fundamental por varias razones:

  • Confianza y Adopción: Los usuarios y stakeholders confían más en modelos que pueden entender. Si un modelo es una "caja negra", su adopción se verá limitada.
  • Depuración y Mejora: Entender las razones detrás de las predicciones erróneas puede ayudar a identificar sesgos en los datos o fallos en el modelo, facilitando su mejora.
  • Cumplimiento Normativo: Regulaciones como el GDPR exigen el "derecho a la explicación" para las decisiones automatizadas, haciendo de la XAI un requisito legal.
  • Descubrimiento Científico: La explicabilidad puede revelar nuevas correlaciones o patrones en los datos que no eran evidentes, impulsando el conocimiento.
  • Detección de Sesgos: Ayuda a identificar y mitigar sesgos injustos en los modelos, promoviendo la equidad.
💡 Consejo: La explicabilidad no es un lujo, es una necesidad para el desarrollo y despliegue responsable de la IA.

📖 LIME: Explicaciones Locales y Agregadas

LIME (Local Interpretable Model-agnostic Explanations) es una técnica que busca explicar las predicciones de cualquier clasificador o regresor de Machine Learning de forma local e interpretable. La clave de LIME es que, para explicar una única predicción, construye un modelo simple y transparente (como un modelo lineal o un árbol de decisión) que se aproxima al comportamiento del modelo complejo en las cercanías de esa predicción específica.

¿Cómo funciona LIME? 🤔

  1. Selección de una instancia: Se elige la instancia cuya predicción queremos explicar.
  2. Generación de datos perturbados: Se crean nuevas instancias perturbando ligeramente la instancia original. Por ejemplo, en datos tabulares, se pueden cambiar valores de características; en imágenes, se pueden apagar o encender "superpíxeles".
  3. Predicción del modelo original: El modelo complejo original predice las etiquetas para estas nuevas instancias perturbadas.
  4. Pesado de las muestras: Las instancias perturbadas se ponderan según su proximidad a la instancia original. Cuanto más cerca esté una perturbación de la instancia original, mayor peso tendrá.
  5. Entrenamiento de un modelo interpretable: Se entrena un modelo interpretable (por ejemplo, regresión lineal, árbol de decisión) sobre las muestras perturbadas, usando sus características y las predicciones del modelo original, ponderadas por su proximidad.
  6. Explicación: Las características y pesos de este modelo interpretable local nos dan la explicación para la predicción de la instancia original.
📌 Nota: LIME es *agnóstico al modelo*, lo que significa que puedes usarlo con cualquier tipo de modelo (Redes Neuronales, Random Forests, SVM, etc.) sin necesidad de modificar el modelo subyacente.
Funcionamiento de LIME 1. Muestreo de Vecindad Vecindad Local Original Perturbaciones Modelo Complejo (Caja Negra / Deep Learning) Predicciones sobre la vecindad Modelo Interpretable (Regresión Lineal Local) Explicación (Output) Característica A Característica B Característica C

🛠️ Implementación de LIME en Python

Para este ejemplo, usaremos un dataset de clasificación tabular y un modelo de Random Forest. Necesitarás instalar lime:

pip install lime

Primero, preparemos nuestros datos y entrenemos un modelo simple:

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris

# Cargar el dataset de Iris como ejemplo
iris = load_iris()
X = iris.data
y = iris.target
feature_names = iris.feature_names
class_names = list(iris.target_names)

# Dividir datos en entrenamiento y prueba
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Entrenar un modelo de Random Forest
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)

# Evaluar el modelo
y_pred = model.predict(X_test)
print(f"Accuracy del modelo: {accuracy_score(y_test, y_pred):.4f}")

# Seleccionar una instancia para explicar (por ejemplo, la primera del conjunto de prueba)
instance_idx = 0
instance_to_explain = X_test[instance_idx]
true_class = y_test[instance_idx]
predicted_class = model.predict(instance_to_explain.reshape(1, -1))[0]

print(f"\nInstancia a explicar: {instance_to_explain}")
print(f"Clase Verdadera: {class_names[true_class]}")
print(f"Clase Predicha: {class_names[predicted_class]}")

Ahora, usemos LIME para explicar una predicción específica:

import lime
import lime.lime_tabular

# Crear un explicador LIME para datos tabulares
explainer = lime.lime_tabular.LimeTabularExplainer(
    training_data=X_train, 
    feature_names=feature_names, 
    class_names=class_names, 
    mode='classification'
)

# Generar la explicación para la instancia seleccionada
# num_features: número de características más importantes a mostrar
# num_samples: número de muestras perturbadas a generar
explanation = explainer.explain_instance(
    data_row=instance_to_explain, 
    predict_fn=model.predict_proba, 
    num_features=len(feature_names), # Mostrar todas las características
    num_samples=1000 # Un buen número para empezar
)

# Mostrar la explicación en texto
print("\nExplicación de LIME para la instancia:")
for feature, weight in explanation.as_list():
    print(f"  {feature}: {weight:.4f}")

# Opcionalmente, visualizar la explicación en un navegador
# explanation.show_in_notebook(show_table=True, show_all=True)

La salida mostrará una lista de características con sus pesos, indicando cuánto contribuyó cada una a la predicción de la clase. Un peso positivo sugiere que la característica empuja la predicción hacia la clase predicha, mientras que un peso negativo la aleja.

Visualización de LIME Si usas un entorno como Jupyter Notebook, puedes ejecutar `explanation.show_in_notebook()` para obtener una visualización interactiva que muestra la contribución de cada característica a la predicción para esa instancia específica. Es muy intuitiva y fácil de entender.

📖 SHAP: Valores de Shapley y Consistencia

SHAP (SHapley Additive exPlanations) es un marco más robusto y teóricamente fundamentado que se basa en los valores de Shapley de la teoría de juegos cooperativos. Los valores de Shapley proporcionan una distribución justa de la "recompensa" (en este caso, la predicción del modelo) entre los "jugadores" (las características del modelo).

¿Cómo funciona SHAP? 🤔

La idea central de SHAP es calcular la contribución promedio de cada característica a la predicción, considerando todas las posibles combinaciones de características. Es decir, el valor SHAP de una característica es el cambio promedio en la predicción del modelo cuando se incluye esa característica en un conjunto aleatorio de otras características.

La fórmula general para el valor de Shapley de una característica j es:

$ \phi_j = \sum_{S \subseteq F \setminus {j}} \frac{|S|!(|F|-|S|-1)!}{|F|!} [f_x(S \cup {j}) - f_x(S)] $

Donde:

  • $F$ es el conjunto de todas las características.
  • $S$ es un subconjunto de características que no incluye la característica j.
  • $f_x(S)$ es la predicción del modelo con solo las características en el conjunto $S$ (y las demás características marginalizadas o "borradas").
  • $f_x(S \cup {j})$ es la predicción del modelo con las características en $S$ y la característica j.
🔥 Importante: Calcular los valores de Shapley exactos es computacionalmente costoso (exponencial). Por ello, SHAP utiliza aproximaciones y algoritmos eficientes (KernelSHAP, TreeSHAP, DeepSHAP, etc.) para distintos tipos de modelos.
Funcionamiento de SHAP (Valores de Shapley) Características (Jugadores) Edad Ingresos Historial MODELO (Caja Negra) Valores SHAP (φ) φ₁ + contribución φ₂ - contribución φₙ + contribución f(x) Predicción Valor Base E[f(X)] Explicación Aditiva: E[f(X)] + φ₁ + φ₂ + ... + φₙ = f(x)

Propiedades deseables de los valores SHAP:

  1. Consistencia: Si un modelo cambia de modo que una característica tiene un mayor impacto marginal en la salida, el valor SHAP de esa característica no debería disminuir.
  2. Suma: La suma de los valores SHAP de todas las características es igual a la diferencia entre la predicción y la predicción base (promedio).
  3. No atribución si no hay efecto: Si una característica no tiene ningún efecto en el modelo, su valor SHAP es cero.

🛠️ Implementación de SHAP en Python

Necesitarás instalar shap:

pip install shap

Continuaremos con el mismo modelo RandomForestClassifier y el dataset Iris.

import shap
import numpy as np

# Inicializar un explicador SHAP. Para modelos basados en árboles, TreeExplainer es eficiente.
# Para otros modelos, KernelExplainer (más lento) o DeepExplainer (para redes neuronales) pueden ser usados.
explainer = shap.TreeExplainer(model)

# Calcular los valores SHAP para el conjunto de prueba
shap_values = explainer.shap_values(X_test)

# Los shap_values son una lista de arrays, uno por cada clase en problemas multiclass
# Para la clase 0, por ejemplo:
# print(shap_values[0].shape) # (n_samples, n_features)

# Para una explicación local (una instancia específica):
instance_shap_values = explainer.shap_values(instance_to_explain.reshape(1, -1))

# Mostrar los valores SHAP para la instancia seleccionada (clase predicha)
print("\nValores SHAP para la instancia seleccionada (para la clase predicha):")
# shap_values[predicted_class] contiene los valores SHAP para cada instancia y característica para esa clase
for i, feature in enumerate(feature_names):
    # instance_shap_values[predicted_class][0] es el array de valores SHAP para la primera instancia y la clase predicha
    print(f"  {feature}: {instance_shap_values[predicted_class][0][i]:.4f}")

# Visualización de la explicación local con un waterfall plot (para una clase específica)
shap.plots.waterfall(shap.Explanation(values=instance_shap_values[predicted_class][0],
                                      base_values=explainer.expected_value[predicted_class],
                                      data=instance_to_explain,
                                      feature_names=feature_names)
)

El waterfall plot muestra cómo cada característica contribuye a la predicción de la instancia, empujándola desde el valor esperado base (promedio de predicción) hacia la predicción final. Los valores en rojo aumentan la predicción, y los valores en azul la disminuyen.

Explicaciones Globales con SHAP ✨

SHAP también es excelente para entender la importancia global de las características. Podemos usar el resumen de SHAP para esto:

# Summary plot - importancia global de las características
# Un `dot plot` (valores de SHAP de características agrupados) y un `bar plot` (importancia promedio)
# shap_values es una lista de arrays para multiclass. Elegimos la clase 0 o un promedio si es relevante.
shap.summary_plot(shap_values, X_test, feature_names=feature_names, class_names=class_names)

# Plot de dependencia de una característica
# Muestra cómo el valor de una característica afecta la predicción, y cómo interactúa con otra característica.
shap.dependence_plot("petal length (cm)", shap_values[predicted_class], X_test, feature_names=feature_names)

El summary plot es una de las visualizaciones más poderosas de SHAP:

  • Cada punto representa un valor SHAP para una característica y una instancia.
  • El color del punto indica el valor de la característica para esa instancia (rojo alto, azul bajo).
  • La posición horizontal indica el valor SHAP (cuánto contribuyó esa característica a la predicción para esa instancia).
  • La dispersión vertical muestra la distribución de la importancia de la característica.

Un dependence plot te permite ver cómo una característica específica afecta la predicción y si hay interacciones con otras características. Por ejemplo, cómo la longitud del pétalo influye en la predicción y si este efecto cambia según el ancho del pétalo.


🤝 LIME vs. SHAP: ¿Cuándo usar cuál?

Ambas herramientas son fantásticas para la explicabilidad, pero tienen filosofías y casos de uso ligeramente diferentes. Aquí una tabla comparativa:

CaracterísticaLIMESHAP
---------
FilosofíaAproximación local con modelo simple.Valores de Shapley (teoría de juegos), atribución justa.
AlcancePrincipalmente explicaciones locales.Locales y globales.
---------
ConsistenciaNo garantizada teóricamente.Garantizada teóricamente.
ComplejidadMás sencillo de entender conceptualmente.Fundamentación matemática más profunda.
---------
ComputacionalMás rápido para explicaciones locales.Más lento para valores exactos, pero hay aproximaciones eficientes.
Tipo de ModeloAgnostic (funciona con cualquier predict_proba).Agnostic (KernelSHAP) o específico (TreeSHAP, DeepSHAP).
---------
SalidaPesos de características del modelo local.Valores de contribución de cada característica.
LIME
SHAP
Facilidad de uso (local) vs. Precisión y robustez (global)

Cuándo elegir LIME:

  • Necesitas una explicación rápida y sencilla para una predicción específica.
  • Tu prioridad es la interpretabilidad conceptual de la explicación local.
  • Trabajas con modelos muy complejos (ej., redes neuronales profundas) y KernelSHAP es demasiado lento.

Cuándo elegir SHAP:

  • Necesitas explicaciones locales y globales robustas y teóricamente sólidas.
  • Quieres comparar la importancia de las características de manera consistente.
  • Trabajas con modelos basados en árboles (TreeSHAP es muy eficiente).
  • La confianza y la atribución precisa son críticas.
⚠️ Advertencia: Aunque LIME es más rápido, su naturaleza agnóstica y local puede llevar a explicaciones que no son "exactamente" consistentes con el modelo global. SHAP, especialmente con sus optimizaciones, es a menudo la opción preferida por su robustez.

🚀 Buenas Prácticas y Consideraciones Finales

Al usar LIME y SHAP (o cualquier herramienta XAI), ten en cuenta lo siguiente:

  1. Contexto es clave: Una explicación por sí sola puede ser engañosa. Siempre interpreta los resultados en el contexto de tu dominio de problema y los datos.
  2. Validación: Siempre que sea posible, valida tus explicaciones con expertos en el dominio para asegurar que tienen sentido.
  3. No es causalidad: La explicabilidad nos muestra correlación y contribución, no causalidad directa. Una característica puede ser importante para la predicción sin ser la causa subyacente del evento.
  4. Balance entre explicabilidad y precisión: A veces, los modelos más explicables (lineales, árboles simples) tienen menor precisión, y los más precisos (redes neuronales, ensembles) son menos explicables. La XAI busca cerrar esa brecha.
  5. Entiende los algoritmos: Conoce cómo LIME y SHAP funcionan internamente para interpretar correctamente sus resultados y elegir el explicador adecuado (KernelSHAP, TreeSHAP, etc.).
Paso 1: Entrenar el Modelo: Desarrolla y valida tu modelo de Machine Learning.
Paso 2: Elegir Herramienta XAI: Decide entre LIME, SHAP u otra herramienta según tus necesidades de explicación (local/global, tipo de modelo, robustez).
Paso 3: Generar Explicaciones: Aplica la herramienta XAI a las predicciones de tu modelo.
Paso 4: Interpretar y Visualizar: Analiza las salidas y crea visualizaciones claras para comunicar los *insights*.
Paso 5: Validar y Actuar: Colabora con expertos del dominio para validar las explicaciones y utiliza los *insights* para mejorar el modelo o tomar decisiones informadas.

La explicabilidad no es solo una moda; es una parte esencial del ciclo de vida del desarrollo de Machine Learning responsable. Al dominar herramientas como LIME y SHAP, no solo construirás modelos más potentes, sino también más confiables y éticos.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!