Visualisation de l'étalonnage de la probabilité prédite d'un modèle

23

Supposons que j'ai un modèle prédictif qui produit, pour chaque instance, une probabilité pour chaque classe. Je reconnais maintenant qu'il existe de nombreuses façons d'évaluer un tel modèle si je veux utiliser ces probabilités pour la classification (précision, rappel, etc.). Je reconnais également qu'une courbe ROC et l'aire sous-jacente peuvent être utilisées pour déterminer dans quelle mesure le modèle différencie les classes. Ce n'est pas ce que je demande.

Je souhaite évaluer l' étalonnage du modèle. Je sais qu'une règle de notation comme le score Brier peut être utile pour cette tâche. C'est OK, et je vais probablement incorporer quelque chose dans ce sens, mais je ne sais pas à quel point ces mesures seront intuitives pour le profane. Je cherche quelque chose de plus visuel. Je veux que la personne qui interprète les résultats puisse voir si oui ou non quand le modèle prédit quelque chose est 70% susceptible de se produire que cela se produit réellement ~ 70% du temps, etc.

J'ai entendu parler (mais jamais utilisé) de parcelles QQ , et au début, je pensais que c'était ce que je cherchais. Cependant, il semble que cela soit vraiment destiné à comparer deux distributions de probabilité . Ce n'est pas directement ce que j'ai. J'ai, pour un tas d'exemples, ma probabilité prédite et ensuite si l'événement s'est réellement produit:

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

Est-ce donc une intrigue QQ vraiment ce que je veux, ou je cherche autre chose? Si un tracé QQ est ce que je devrais utiliser, quelle est la bonne façon de transformer mes données en distributions de probabilité?

J'imagine que je pourrais trier les deux colonnes par probabilité prédite, puis créer des bacs. Est-ce le genre de chose que je devrais faire, ou suis-je en train de penser quelque part? Je connais diverses techniques de discrétisation, mais existe-t-il une manière spécifique de discrétiser dans les bacs qui est standard pour ce genre de chose?

Michael McGowan
la source

Réponses:

19

Votre pensée est bonne.

John Tukey a recommandé le regroupement par moitiés: divisez les données en moitiés supérieure et inférieure, puis divisez ces moitiés, puis divisez les moitiés extrêmes de manière récursive. Comparé au binning d'égale largeur, cela permet une inspection visuelle du comportement de la queue sans consacrer trop d'éléments graphiques à la majeure partie des données (au milieu).

Voici un exemple (en utilisant R) de l'approche de Tukey. (Ce n'est pas exactement la même chose: il a mis en œuvre mletterun peu différemment.)

Tout d'abord, créons des prédictions et des résultats conformes à ces prédictions:

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

L'intrigue n'est pas très informative, car toutes les actualvaleurs sont, bien sûr, soit (ne s'est pas produit) ou (s'est produit). (Il apparaît comme l'arrière-plan des cercles ouverts gris dans la première figure ci-dessous.) Ce tracé doit être lissé. Pour ce faire, nous regroupons les données. La fonction fait le fractionnement par moitié. Son premier argument est un tableau de rangs compris entre 1 et (le deuxième argument). Il renvoie des identificateurs uniques (numériques) pour chaque bac: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
}

En utilisant cela, nous regroupons à la fois les prévisions et les résultats et faisons la moyenne de chacun dans chaque groupe. En cours de route, nous calculons les populations de bacs:

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

Pour symboliser efficacement l'intrigue, nous devons rendre les zones de symboles proportionnelles au nombre de casiers. Il peut également être utile de varier un peu les couleurs des symboles:

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

Avec ceux-ci en main, nous améliorons maintenant l'intrigue précédente:

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

Figure

Comme exemple d'une mauvaise prédiction, modifions les données:

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

La répétition de l'analyse produit ce graphique dans lequel les écarts sont clairs:

Figure 2

Ce modèle a tendance à être trop optimiste (les résultats moyens pour les prévisions de 50% à 90% sont trop bas). Dans les quelques cas où la prédiction est faible (moins de 30%), le modèle est trop pessimiste.

whuber
la source
(+1) Très bien, merci. Je pense que les couleurs peuvent distraire un peu de l'objectif, mais le reste était une bonne idée et une très belle explication.
Michael McGowan
Michael, j'ai trouvé qu'une certaine couleur était nécessaire pour aider à voir les très petits cercles qui apparaissent à chaque extrémité. Une couleur constante accomplirait cela bien sûr. Remplacez-le simplement col=colorspar la couleur souhaitée, par exemple col="Red".
whuber
+1, c'est très sympa. Cependant, je ne comprends pas très bien pourquoi la ligne de référence est une ligne droite simple à 45 degrés, au lieu de la ligne de régression logistique appropriée, ou un loess? Je pense que ce seraient des références plus appropriées pour juger de la qualité des prévisions.
gung - Rétablir Monica
pp±[0,1]×[0,1]
whuber
p(1-p)/npn
4

Une autre option est la régression isotonique. Elle est similaire à la réponse de whuber, sauf que les bacs sont générés dynamiquement au lieu de se diviser en deux, avec une exigence que les sorties augmentent strictement.

Cette utilisation principale de la régression isotonique est de recalibrer vos probabilités si elles sont mal calibrées, mais elle peut également être utilisée pour la visualisation. Fondamentalement, si la ligne de régression isotonique suit à peu près la ligne Y = X, alors vos probabilités sont correctement calibrées.

Régression isotonique sur les probabilités

Il s'agit de la régression isotonique appliquée au problème montré par 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
la source