Visualizando la calibración de la probabilidad predicha de un modelo

23

Supongamos que tengo un modelo predictivo que produce, para cada caso, una probabilidad para cada clase. Ahora reconozco que hay muchas formas de evaluar ese modelo si quiero usar esas probabilidades para la clasificación (precisión, recuperación, etc.). También reconozco que una curva ROC y el área debajo de ella se pueden usar para determinar qué tan bien el modelo diferencia entre clases. Esos no son lo que estoy preguntando.

Estoy interesado en evaluar la calibración del modelo. que una regla de puntuación como el puntaje de Brier puede ser útil para esta tarea. Eso está bien, y probablemente incorporaré algo en ese sentido, pero no estoy seguro de cuán intuitivas serán esas métricas para el lego. Estoy buscando algo más visual. Quiero que la persona que interpreta los resultados pueda ver si el modelo predice que es probable que suceda o no un 70% de lo que realmente sucede ~ 70% del tiempo, etc.

Escuché (pero nunca usé) tramas QQ , y al principio pensé que esto era lo que estaba buscando. Sin embargo, parece que realmente está destinado a comparar dos distribuciones de probabilidad . Eso no es directamente lo que tengo. Tengo, para un montón de casos, mi probabilidad pronosticada y luego si el evento realmente ocurrió:

Index    P(Heads)    Actual Result
    1          .4            Heads
    2          .3            Tails
    3          .7            Heads
    4         .65            Tails
  ...         ...              ...

Entonces, ¿es una trama QQ realmente lo que quiero, o estoy buscando otra cosa? Si un gráfico QQ es lo que debería usar, ¿cuál es la forma correcta de transformar mis datos en distribuciones de probabilidad?

Me imagino que podría ordenar ambas columnas por probabilidad pronosticada y luego crear algunos contenedores. ¿Es ese el tipo de cosas que debería estar haciendo, o estoy pensando en alguna parte? Estoy familiarizado con varias técnicas de discretización, pero ¿hay alguna forma específica de discretizar en contenedores que sea estándar para este tipo de cosas?

Michael McGowan
fuente

Respuestas:

19

Tu pensamiento es bueno.

John Tukey recomendó el binning por mitades: divide los datos en mitades superior e inferior, luego divide esas mitades, luego divide las mitades extremas de forma recursiva. En comparación con el binning de igual ancho, esto permite la inspección visual del comportamiento de la cola sin dedicar demasiados elementos gráficos a la mayor parte de los datos (en el medio).

Aquí hay un ejemplo (usando R) del enfoque de Tukey. (No es exactamente lo mismo: implementó mletterun poco diferente).

Primero, creemos algunas predicciones y algunos resultados que se ajusten a esas predicciones:

set.seed(17)
prediction <- rbeta(500, 3/2, 5/2)
actual <- rbinom(length(prediction), 1, prediction)
plot(prediction, actual, col="Gray", cex=0.8)

actual0 01mletterrn

mletter <- function(r,n) {
    lower <-  2 + floor(log(r/(n+1))/log(2))
    upper <- -1 - floor(log((n+1-r)/(n+1))/log(2))
    i <- 2*r > n
    lower[i] <- upper[i]
    lower
}

Usando esto, agrupamos las predicciones y los resultados y promediamos cada uno dentro de cada contenedor. En el camino, calculamos poblaciones bin:

classes <- mletter(rank(prediction), length(prediction))
pgroups <- split(prediction, classes)
agroups <- split(actual, classes)
bincounts <- unlist(lapply(pgroups, length)) # Bin populations
x <- unlist(lapply(pgroups, mean))           # Mean predicted values by bin
y <- unlist(lapply(agroups, mean))           # Mean outcome by bin

Para simbolizar la trama de manera efectiva, debemos hacer que las áreas de símbolos sean proporcionales a los conteos de bin. También puede ser útil variar un poco los colores de los símbolos, de donde:

binprop <- bincounts / max(bincounts)
colors <- -log(binprop)/log(2)
colors <- colors - min(colors)
colors <- hsv(colors / (max(colors)+1))

Con esto en mano, ahora mejoramos la trama anterior:

abline(0,1, lty=1, col="Gray")                           # Reference curve
points(x,y, pch=19, cex = 3 * sqrt(binprop), col=colors) # Solid colored circles
points(x,y, pch=1, cex = 3 * sqrt(binprop))              # Circle outlines

Figura

Como ejemplo de una mala predicción, cambiemos los datos:

set.seed(17)
prediction <- rbeta(500, 5/2, 1)
actual <- rbinom(length(prediction), 1, 1/2 + 4*(prediction-1/2)^3)

La repetición del análisis produce este gráfico en el que las desviaciones son claras:

Figura 2

Este modelo tiende a ser demasiado optimista (el resultado promedio para las predicciones en el rango del 50% al 90% es demasiado bajo). En los pocos casos donde la predicción es baja (menos del 30%), el modelo es demasiado pesimista.

whuber
fuente
(+1) Muy bien, gracias. Creo que los colores pueden distraer un poco el propósito, pero el resto fue una buena idea y una muy buena explicación.
Michael McGowan
Michael, descubrí que era necesario un poco de color para ayudar a ver los círculos muy pequeños que aparecen en cada extremo. Un color constante lograría esto, por supuesto. Simplemente reemplácelo col=colorspor el color que desee, como col="Red".
whuber
+1, esto es muy bueno. Sin embargo, no entiendo por qué la línea de referencia es una línea simple y recta de 45 grados, en lugar de la línea de regresión logística adecuada, o un loess. Creo que esas serían referencias más apropiadas para juzgar la calidad de las predicciones.
gung - Restablecer Monica
pagspags±[0 0,1]×[0 0,1]
whuber
pags(1-pags)/ /nortepagsnorte
4

Otra opción es la regresión isotónica. Es similar a la respuesta de Whuber, excepto que los contenedores se generan dinámicamente en lugar de dividirse en mitades, con el requisito de que los resultados estén aumentando estrictamente.

Este uso principal de la regresión isotónica es recalibrar sus probabilidades si se demuestra que están mal calibradas, pero también se puede usar para la visualización. Básicamente, si la línea de regresión isotónica sigue aproximadamente la línea Y = X, entonces sus probabilidades están correctamente calibradas.

Regresión isotónica sobre probabilidades

Esta es la regresión isotónica aplicada al problema mostrado por Whuber.

import numpy as np
import matplotlib.pyplot as plt
from sklearn.isotonic import IsotonicRegression

prediction = np.random.beta(3.0/2.0, 5.0/2.0, size=500)
actual = np.random.binomial(1,prediction, len(prediction))
plt.scatter(prediction, actual,  facecolors='none', edgecolors=[0.3,0.3,0.3], label='Data')

ir = IsotonicRegression()
isotonic = ir.fit_transform(prediction, actual)
plt.plot(prediction, isotonic,'ok', label='Isotonic Fit')

plt.xlabel('Prediction')
plt.ylabel('Actual')
plt.plot([0,1],[0,1], '--k', label='y=x line')
plt.legend(loc = 'center left')

http://fa.bianp.net/blog/2013/isotonic-regression/

http://stat.wikia.com/wiki/Isotonic_regression

Bscan
fuente