Python & Data Science
Explicabilidad En revisión

¿Por qué el modelo dijo que no? Explicando decisiones de caja negra a tu jefe sin matemáticas

El problema de la ‘caja negra’: por qué el ‘confía en mí’ no es suficiente

En los últimos tres artículos, el equipo de ciencia de datos construyó un kit de herramientas de explicabilidad para la denegación del préstamo de Maria. Usaron valores SHAP para descomponer la predicción de Maria en las contribuciones individuales de cada característica. Compararon SHAP con LIME en cuanto a velocidad frente a consistencia. Y usaron curvas PDP y ICE para ver cómo los ingresos y otras características influyen en las probabilidades de aprobación de todos los solicitantes, no solo de Maria. Ahora todo encaja. Mr. Owens necesita tomar ese trabajo técnico y convertirlo en la explicación real que se le dará a Maria, una que también satisfaga a un regulador.

Imagina que eres un oficial de préstamos en un banco local. Maria, una cliente desde hace mucho tiempo, entra, solicita un préstamo para pequeñas empresas y, cinco minutos después, tu pantalla muestra un destello rojo brillante de “RECHAZADO”.

Maria te mira a los ojos y pregunta: “¿Por qué? Mi crédito es decente y mis ingresos han aumentado.” Mr. Owens está parado detrás de ti, esperando la misma respuesta. También lo está el regulador que pidió documentación sobre cada denegación automatizada este trimestre.

Si tu única respuesta es “No lo sé, la computadora simplemente lo dijo”, has perdido más que a un cliente. Has perdido su confianza. Y Mr. Owens no tiene nada que mostrarle al regulador. En el mundo de los negocios, “confía en mí” es una frase peligrosa. Un modelo que toma decisiones a ciegas es un pasivo, ya sea en la banca, el cuidado de la salud, el comercio minorista o cualquier otro lugar.

Una “caja negra” no es magia. Generalmente es solo un modelo con tantas partes en movimiento — miles de ramas de decisión o millones de pesos — que el cerebro humano no puede seguirles el rastro a todas a la vez. Si no puedes explicarlo, tus stakeholders no lo usarán, sin importar lo preciso que sea.

Así que construyamos un modelo “desordenado” que sea imposible de explicar con solo mirarlo. Usaremos un Random Forest, que es esencialmente un bosque de cientos de pequeños árboles de decisión gritando sus opiniones a la vez.

import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestClassifier

# Let's create a fake dataset of loan applicants
# Features: Credit Score, Annual Income (in $k), and Debt-to-Income Ratio
data = {
    'credit_score': [720, 600, 550, 800, 620, 710, 590, 750],
    'income_k': [80, 45, 30, 120, 50, 85, 40, 95],
    'debt_ratio': [0.2, 0.4, 0.6, 0.1, 0.3, 0.25, 0.5, 0.15],
    'approved': [1, 0, 0, 1, 0, 1, 0, 1]
}
df = pd.DataFrame(data)

# Train a Random Forest with 100 trees
# Even with 3 features, 100 trees make it a 'black box'
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(df.drop('approved', axis=1), df['approved'])

# Predict for a new customer
new_customer = np.array([[650, 55, 0.35]])
prediction = model.predict(new_customer)
probability = model.predict_proba(new_customer)[0][1]

print(f"Prediction: {'Approved' if prediction[0] == 1 else 'Rejected'}")
print(f"Probability of Approval: {probability:.2f}")
  • data = {...} — Un diccionario de Python donde cada clave es un nombre de columna y cada valor es una lista de los valores de esa columna. Esta es la forma más sencilla de definir datos tabulares a mano.
  • pd.DataFrame(data) — Convierte el diccionario en un DataFrame de pandas — una tabla donde cada clave se convierte en una columna y cada lista se convierte en las filas de esa columna.
  • RandomForestClassifier(n_estimators=100, random_state=42) — Crea (pero aún no entrena) un bosque aleatorio con 100 árboles de decisión. random_state=42 inicializa el bootstrapping interno para que el bosque sea idéntico en cada ejecución.
  • model.fit(df.drop('approved', axis=1), df['approved']) — Entrena el bosque en todas las características excepto approved (las características) contra approved (la etiqueta). axis=1 significa “eliminar una columna”.
  • new_customer = np.array([[650, 55, 0.35]]) — Crea un arreglo NumPy 2D con una fila y tres columnas: puntaje crediticio 650, ingresos $55k, ratio de deuda 0.35. En la narrativa, estos son los valores reales de Maria.
  • model.predict(new_customer) — Devuelve un arreglo de etiquetas de clase predichas (0 = Rechazado, 1 = Aprobado) para cada fila de entrada.
  • model.predict_proba(new_customer)[0][1]predict_proba devuelve un arreglo de forma (n_rows, n_classes). [0] selecciona la primera (y única) fila; [1] selecciona la probabilidad de la clase 1 (Aprobado).

La salida nos dice que Maria fue rechazada con solo un 3% de probabilidad de aprobación. ¿Pero por qué? Mirar los 100 árboles dentro de esa variable model no te dirá si fue el ratio de deuda o que sus ingresos fueran un poco demasiado bajos. Esta es la parte más difícil del aprendizaje automático moderno: el trade-off entre la precisión y la comprensión.

SHAP: dándole a cada característica su ‘recibo’

Para resolver esto, usamos SHAP (SHapley Additive exPlanations). La forma más fácil de pensarlo es como un proyecto grupal.

Imagina a cuatro amigos construyendo una casa. Al final, la casa tiene 20 pies de altura. ¿Cuánto contribuyó cada persona? No puedes simplemente mirar la altura final. Tienes que verificar qué tan alta habría sido la casa si el Amigo A no hubiera ido, o si el Amigo B hubiera trabajado solo.

SHAP trata las características de tu modelo (como el puntaje de crédito o los ingresos) como compañeros de equipo. Calcula un “pago” para cada característica comparando la predicción cuando esa característica está presente frente a cuando falta. Lo que esto significa en realidad: dividimos la predicción final en una suma de sus partes. Cada característica obtiene un “recibo” por su contribución.

import shap

# Initialize the explainer
explainer = shap.TreeExplainer(model)

# Calculate SHAP values for our new customer
shap_values = explainer.shap_values(new_customer)

# Let's look at the contributions for the 'Rejected' class
# shap_values[1] corresponds to the 'Approved' probability
feature_names = ['credit_score', 'income_k', 'debt_ratio']
contributions = pd.DataFrame({
    'feature': feature_names,
    'contribution': shap_values[1][0]
})

print(contributions)
  • shap.TreeExplainer(model) — Crea un explicador SHAP especializado para modelos basados en árboles (bosques aleatorios, gradient boosting, XGBoost, etc.). Utiliza el algoritmo exacto TreeSHAP, que es de tiempo polinomial y mucho más rápido que el KernelExplainer de propósito general.
  • explainer.shap_values(new_customer) — Calcula los valores SHAP para cada característica en la fila única new_customer. Para un clasificador binario, esto devuelve una lista de dos arreglos: el índice 0 contiene las contribuciones hacia la clase 0 (Rechazado), el índice 1 hacia la clase 1 (Aprobado).
  • shap_values[1][0] — El índice [1] selecciona el arreglo de la clase Aprobado; [0] toma los valores SHAP para la primera (y única) muestra — la fila de Maria.
  • pd.DataFrame({'feature': feature_names, 'contribution': shap_values[1][0]}) — Construye un DataFrame de dos columnas que empareja cada nombre de característica con su contribución SHAP, de modo que la salida impresa sea legible por humanos en lugar de ser un simple arreglo NumPy.

Al ejecutar esto, verás números como -0.12 para credit_score o +0.05 para income_k. Un número negativo significa que esa característica arrastró la puntuación hacia abajo (haciendo el rechazo más probable), mientras que un número positivo la empujó hacia arriba. No más conjeturas: tenemos el recibo de la denegación de Maria.

Este artículo no introduce nuevas matemáticas: aplica las herramientas de los primeros tres artículos a una conversación real con las partes interesadas. Aquí hay un resumen de los términos clave utilizados en todo el clúster para que puedas conectar la explicación del negocio con sus raíces técnicas.

Inglés sencilloSímbolo estadísticoEquivalente en PythonHerramienta
Valor SHAP (crédito asignado a la característica ii para una predicción)ϕi\phi_ishap_values[1][0, i]SHAP (Artículo 1)
Línea base del modelo / predicción promedioE[f(x)]\mathbb{E}[f(x)]explainer.expected_value[1]SHAP (Artículo 1)
Garantía aditiva: base + todos los valores SHAP = predicciónf(x)=E[f(x)]+iϕif(x) = \mathbb{E}[f(x)] + \sum_i \phi_ibase_value + shap_values[1][0].sum()SHAP (Artículo 1)
Peso lineal local de LIME para la característica iiwiw_iweight en exp.as_list()LIME (Artículo 2)
Dependencia parcial (predicción promedio a medida que varía la característica xSx_S)fˉS(xS)\bar{f}_S(x_S)valor y en la curva PDPPDP/ICE (Artículo 3)
Predicción de una fila a medida que varía xSx_S (una curva ICE)f(xS,xC(i))f(x_S, x_C^{(i)}) para un ii fijoUna línea en el gráfico kind='both'PDP/ICE (Artículo 3)

Cómo se conectan en este artículo: El Force Plot que el Sr. Owens le muestra a Maria es una representación visual de ϕi\phi_i para cada característica — los mismos valores SHAP del Artículo 1. El Summary Plot que le muestra al equipo de cumplimiento agrega ϕi|\phi_i| entre todos los solicitantes, la misma agregación introducida en el Artículo 1 y extendida en el Artículo 3. Las curvas PDP del Artículo 3 proporcionan el telón de fondo de la “forma del efecto” que le da al recibo individual de SHAP su contexto más amplio.

Leyendo el ‘Force Plot’: el tira y afloja por una decisión

Ahora, ¿cómo le muestras esto al Sr. Owens — y, eventualmente, a María? No les muestras una hoja de cálculo llena de decimales. Les muestras un Force Plot.

Piénsalo como un tira y afloja visual.

  1. El Valor Base: El punto de partida — la tasa de aprobación promedio de todos los clientes en nuestro historial.
  2. Flechas Rojas: Características que empujan el puntaje hacia arriba, hacia la aprobación.
  3. Flechas Azules: Características que jalan el puntaje hacia abajo, hacia el rechazo.

La predicción final es el punto donde la cuerda se detuvo después del tirón.

# Note: In a real notebook, this displays an interactive HTML graphic
shap.initjs()
shap.force_plot(
    explainer.expected_value[1], 
    shap_values[1][0], 
    new_customer, 
    feature_names=feature_names
)
  • shap.initjs() — Inicializa el backend de gráficos en JavaScript requerido para los force plots interactivos (no Matplotlib) de SHAP. Es necesario llamarlo una vez por sesión de notebook antes de invocar force_plot sin matplotlib=True.
  • shap.force_plot(...) — Dibuja el clásico force plot de SHAP: una barra horizontal que comienza en el valor base, con flechas rojas empujando hacia la derecha (hacia una mayor probabilidad de aprobación) y flechas azules empujando hacia la izquierda (hacia una menor probabilidad).
  • explainer.expected_value[1] — La probabilidad de aprobación predicha promedio del modelo en todo el conjunto de datos de fondo. Esto ancla el borde izquierdo del gráfico en la línea base. El índice [1] selecciona la clase positiva (Aprobado).
  • shap_values[1][0] — Los valores SHAP de María para la clase Aprobado: las longitudes y direcciones de cada flecha.
  • new_customer — Los valores de las características de María, mostrados como etiquetas en cada flecha para que el lector pueda ver qué valor de cada característica impulsó la contribución.
  • feature_names=feature_names — Pasa las etiquetas de las columnas para que el gráfico anote las flechas con nombres legibles por humanos en lugar de índices enteros.

Puedes decirle al Sr. Owens: “El cliente promedio tiene un 50% de probabilidad de aprobación. María cayó al 3% porque su puntaje crediticio — la flecha azul grande — jaló el puntaje significativamente hacia abajo, a pesar de que su ingreso (la flecha roja pequeña) intentó empujarlo hacia arriba nuevamente”. Esa es la respuesta que él puede darle a María, y la que puede poner en el archivo del regulador.

La vista ‘global’: ¿qué es lo que más le importa al modelo?

Explicar una decisión está muy bien para Maria, pero el Sr. Owens quiere saber si el modelo está sesgado o tiene errores antes de salir a producción, y el regulador hará la misma pregunta. Quieren ver la “personalidad” del modelo.

Un Summary Plot (gráfico de resumen, a menudo llamado Beeswarm plot o gráfico de enjambre) hace esto. Pasa de una decisión específica a todo el modelo. El gráfico muestra si el modelo está “obsesionado” con una variable en particular.

# We'll calculate SHAP values for the whole training set to see the big picture
shap_values_all = explainer.shap_values(df.drop('approved', axis=1))

# Generate the summary plot
shap.summary_plot(shap_values_all[1], df.drop('approved', axis=1))
  • explainer.shap_values(df.drop('approved', axis=1)) — Calcula los valores SHAP para cada fila en el conjunto de entrenamiento (no solo la única fila de Maria), produciendo un arreglo (n_rows, n_features) por clase. Esta es la misma llamada utilizada en el Artículo 1 para el gráfico de barras resumen.
  • shap.summary_plot(shap_values_all[1], df.drop('approved', axis=1)) — Dibuja el gráfico de enjambre: cada punto es el valor SHAP de un solicitante para esa característica, coloreado según el valor real de la característica (rojo = alto, azul = bajo). Las características se clasifican de arriba hacia abajo por el valor absoluto medio de SHAP — la lista general de prioridades del modelo.

El gráfico clasifica las características por importancia. Si credit_score ocupa el primer lugar, ese es el principal impulsor del modelo.

¿Qué pasa si una característica como “Zip Code” (código postal) aparece en la cima en su lugar? Eso es una señal de alerta. El modelo podría estar usando la ubicación como un proxy de la raza o el nivel de ingresos, lo que podría causar problemas legales. Puedes comparar las prioridades del modelo con la intuición de un experto humano. Si le importa más el día de la semana en que se solicitó el préstamo que la deuda de la persona, el modelo es “tonto” y necesita corrección.

¿A quién le muestras qué explicación?

El equipo ha construido ahora tres herramientas de explicabilidad diferentes a lo largo de esta serie — valores de SHAP, LIME y curvas PDP/ICE. Pero el Sr. Owens se enfrenta a una pregunta práctica: ¿cuál les muestra realmente a cada audiencia? La respuesta depende de quién esté sentado al otro lado de la mesa.

AudienciaLo que necesitanMejor herramientaPor qué
María (la solicitante rechazada)Una razón clara y humana para su rechazo — sin jergaGráfico de fuerza (SHAP)Un tira y afloja visual; ella puede ver qué características la empujaron hacia el “No” sin ninguna matemática. La garantía aditiva significa que la explicación es demostrablemente correcta, no una aproximación.
El regulador / equipo de cumplimientoPrueba de que el modelo no utiliza variables prohibidas o proxy; documentación por rechazoGráfico de resumen (SHAP global) + Gráfico de fuerza (por rechazo)El gráfico de resumen demuestra que las prioridades globales del modelo son legítimas; el gráfico de fuerza documenta cada rechazo individual. La consistencia matemática de SHAP es la respuesta de calidad legal aquí — la inestabilidad de LIME no sobreviviría a una auditoría.
Sr. Owens (gerencia interna)Una verificación rápida durante las operaciones; comprender el comportamiento general del modeloCurvas PDP/ICE para la forma + LIME para la rapidezLos PDP muestran “¿cómo afectan los ingresos a la aprobación de todos los solicitantes?” en una sola línea; LIME ofrece una explicación rápida y aproximada cuando un cliente está al teléfono y no hay tiempo para esperar a SHAP.
El equipo de ciencia de datos (depuración)Descomposición completa; detección de interacciones; auditoría de sesgosGráficos de dependencia de SHAP + Curvas ICELos gráficos de dependencia de SHAP revelan automáticamente las interacciones (coloreando por la segunda característica más correlacionada); las curvas ICE revelan la heterogeneidad que el PDP oculta.

Cuándo simplificar

  • María no necesita las matemáticas. Ella necesita escuchar: “Su puntaje crediticio de 650 estaba por debajo de nuestro umbral, y su relación deuda-ingresos de 0.35 estaba por encima del límite del modelo para su tramo de ingresos.” El gráfico de fuerza es el elemento visual detrás de esa oración — ella nunca ve un valor de Shapley.
  • El regulador necesita la prueba. Necesita ver que el gráfico de fuerza tiene la garantía matemática de descomponer la predicción (la aditividad de SHAP), y que el gráfico de resumen no muestra variables proxy en la parte superior. Aquí es donde la consistencia de SHAP — no la aproximación de LIME — importa.
  • El Sr. Owens necesita el patrón. El PDP del Artículo 3 (“¿cómo afectan los ingresos a la aprobación en general?”) más el gráfico de fuerza para este rechazo específico le da tanto el bosque como el árbol en una sola reunión.

La versión corta

Muestra a Maria el gráfico de fuerza. Muestra al regulador el gráfico de fuerza más el gráfico de resumen. Muestra a Mr. Owens la curva PDP más el gráfico de fuerza. Usa LIME solo cuando necesites una aproximación rápida y no puedas esperar a SHAP. La herramienta “correcta” depende de quién pregunte — y de qué harán con la respuesta.

El ‘¿y qué?’: cómo convertir gráficos en acciones de negocio

Al Sr. Owens no le importan los valores de Shapley ni la teoría de juegos. Le importan el riesgo y los resultados — y ahora mismo, quiere darle a Maria una respuesta honesta.

Aquí te mostramos cómo poner estas herramientas en práctica:

  • No muestres el código; muestra el tira y afloja. Usa el Force Plot para guiar a los stakeholders a través de decisiones individuales. Convierte un “no” en un “no, porque…”
  • Usa el Summary Plot como salvaguarda. Antes de desplegar el modelo, muestra sus características principales a tu equipo legal o de cumplimiento. Esto demuestra que no estás utilizando datos prohibidos.
  • Depura el comportamiento “tonto”. Si SHAP muestra que el modelo ignora los ingresos, es posible que tengas un problema de calidad de datos que pasó desapercibido durante el entrenamiento.

La explicabilidad no es un “plus”. Es lo que permite que una empresa confíe en las matemáticas que has construido.

Lo que aprendimos:

  1. Las cajas negras son simplemente modelos complejos que no podemos rastrear mentalmente.
  2. SHAP le da a cada característica un recibo por su contribución.
  3. Los Force Plots muestran el tira y afloja detrás de una única decisión.
  4. Los Summary Plots revelan la personalidad general del modelo y sus posibles sesgos.

Maria está sentada al otro lado del escritorio del Sr. Owens. Él no le muestra un beeswarm plot ni una lista de valores de Shapley. Le muestra una sola imagen — el force plot — y le dice: “Tu puntaje crediticio de 650 hizo que tus probabilidades de aprobación cayeran significativamente. Tus ingresos de $55,000 empujaron hacia arriba, pero no lo suficiente para superar el índice de deuda de 0.35, que el modelo marcó por estar por encima del umbral para tu rango de ingresos.” Maria asiente. Puede que no le encante la respuesta, pero tiene una — específica para ella, no un simple “la computadora lo dijo”. El Sr. Owens archiva el mismo force plot en el expediente de documentación del regulador, junto con el summary plot que confirma que las prioridades globales del modelo son sólidas. La próxima vez que se niegue un préstamo, sabe a qué herramienta recurrir y qué historia contar. La caja negra no es magia. Son solo matemáticas — y ahora todos en la sala pueden verlo.

Comprueba tu comprensión

Las preguntas a continuación avanzan desde el simple recuerdo hasta el diseño de formato abierto, siguiendo aproximadamente la Taxonomía de Bloom.

Recordar ¿Qué representan las flechas rojas y las flechas azules en un SHAP Force Plot?

Entender Con tus propias palabras, explica la analogía del artículo de los “cuatro amigos construyendo una casa”: ¿cómo capta lo que un valor SHAP realmente mide para una característica?

Aplicar Usando el formato de tabla de contribuciones del artículo (característica, contribución), si credit_score tiene una contribución de -0.15 y income_k tiene +0.04, ¿qué característica está empujando más fuerte hacia el rechazo y por cuánto más?

Analizar El artículo menciona que un Summary Plot que muestre “Zip Code” como la característica principal sería “una gran bandera roja” porque podría ser “un proxy de la raza o el nivel de ingresos”. Explica paso a paso por qué una característica puede crear un riesgo legal o de equidad (fairness) incluso cuando nunca fue etiquetada como un atributo sensible y al modelo nunca se le habló de la raza directamente: ¿qué mecanismo permite que una variable proxy introduzca esa información de contrabando?

Evaluar El conjunto de datos de ejemplo del artículo tiene solo 8 filas, pero se utiliza para demostrar un Random Forest de “caja negra” con 100 árboles. Critica esta elección pedagógica: con tan pocos ejemplos de entrenamiento, ¿la explicación SHAP del modelo está revelando realmente patrones aprendidos genuinos, o podría estar reflejando simplemente el ruido del sobreajuste (overfitting) de un conjunto de datos demasiado pequeño para generalizar?

Crear Diseña un paquete de explicaciones orientado a las partes interesadas (siguiendo el patrón de Force Plot + Summary Plot del artículo) para un modelo diferente: un modelo de reclamaciones de seguros que acaba de denegar una reclamación. Describe qué le mostrarías al reclamante (explicación individual) frente a lo que le mostrarías a tu equipo de cumplimiento normativo (explicación global/agregada) y por qué esas dos audiencias necesitan vistas diferentes del mismo modelo.


Artículos relacionados


Referencias y lecturas adicionales

  • Lundberg, S. M., & Lee, S.-I. (2017). “A Unified Approach to Interpreting Model Predictions.” Advances in Neural Information Processing Systems 30 (NeurIPS 2017). https://arxiv.org/abs/1705.07874 — El artículo fundamental que introduce los valores SHAP y el algoritmo TreeSHAP; la base matemática detrás de cada force plot y summary plot en este artículo.
  • Ribeiro, M. T., Singh, S., & Guestrin, C. (2016). “‘Why Should I Trust You?’: Explaining the Predictions of Any Classifier.” Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD ‘16). https://arxiv.org/abs/1602.04938 — El artículo fundamental que introduce LIME; relevante aquí por la discusión sobre el equilibrio entre cuándo es aceptable una aproximación local rápida frente a cuándo se requiere la consistencia de SHAP.
  • Friedman, J. H. (2001). “Greedy Function Approximation: A Gradient Boosting Machine.” Annals of Statistics, 29(5), 1189–1232. https://projecteuclid.org/euclid.aos/1013203451 — El artículo fundamental que introduce los Partial Dependence Plots; el trasfondo de la “forma del efecto” que le muestra a Mr. Owens el patrón global detrás de la negación individual de Maria.
  • Molnar, C. (2022). Interpretable Machine Learning: A Guide for Making Black Box Models Explainable. https://christophm.github.io/interpretable-ml-book/ — Un libro de texto en línea, gratuito y completo que cubre SHAP, LIME, PDP, ICE y el panorama más amplio de la explicabilidad; una referencia esencial para cualquiera que construya un flujo de trabajo de explicabilidad reproducible como el que describe este artículo.
  • shap library documentation. https://shap.readthedocs.io — Referencia completa de la API para TreeExplainer, force_plot, summary_plot y todas las demás utilidades de SHAP utilizadas a lo largo de esta serie.
  • Kaggle: “Home Credit Default Risk” competition. https://www.kaggle.com/c/home-credit-default-risk — Un conjunto de datos del mundo real sobre incumplimiento de préstamos donde las explicaciones con SHAP son ampliamente demostradas en notebooks con mejores puntajes; un sandbox excelente para practicar el flujo de trabajo de extremo a extremo, desde el force plot hasta el summary plot y la conversación con las partes interesadas.

Esta traducción fue generada automáticamente y puede contener errores. Si el idioma inglés es tu preferencia, puedes leer el artículo original en inglés .

«Aplica lo que aprendiste» es para suscriptores Supporter e Insider.

Suscríbete para desbloquear los ejercicios de este artículo.

Ver planes

¿Buscas otra cosa?

Busca en todos los artículos por título, resumen o tema.