So berechnen Sie die Fläche unter der Kurve (AUC) oder die c-Statistik von Hand


78

Ich bin daran interessiert, die Fläche unter der Kurve (AUC) oder die c-Statistik von Hand für ein binäres logistisches Regressionsmodell zu berechnen.

Zum Beispiel habe ich im Validierungsdatensatz den wahren Wert für die abhängige Variable, Aufbewahrung (1 = beibehalten; 0 = nicht beibehalten), sowie einen vorhergesagten Aufbewahrungsstatus für jede Beobachtung, die durch meine Regressionsanalyse unter Verwendung eines Modells generiert wurde gebaut mit dem Trainingsset (dies wird von 0 bis 1 reichen).

Meine anfänglichen Gedanken waren, die "richtige" Anzahl von Modellklassifikationen zu identifizieren und einfach die Anzahl der "richtigen" Beobachtungen durch die Anzahl der Gesamtbeobachtungen zu dividieren, um die c-Statistik zu berechnen. Mit "richtig" ist dies eine "richtige" Klassifizierung, wenn der wahre Aufbewahrungsstatus einer Beobachtung = 1 und der vorhergesagte Aufbewahrungsstatus> 0,5 ist. Wenn außerdem der wahre Aufbewahrungsstatus einer Beobachtung = 0 und der vorhergesagte Aufbewahrungsstatus <0,5 ist, ist dies auch eine "korrekte" Klassifizierung. Ich gehe davon aus, dass ein "Unentschieden" auftreten würde, wenn der vorhergesagte Wert = 0,5 ist, aber dieses Phänomen tritt in meinem Validierungsdatensatz nicht auf. Andererseits wären "falsche" Klassifizierungen, wenn der wahre Aufbewahrungsstatus einer Beobachtung = 1 ist und der vorhergesagte Aufbewahrungsstatus <0 ist. 5 oder wenn der wahre Aufbewahrungsstatus für ein Ergebnis = 0 und der vorhergesagte Aufbewahrungsstatus> 0,5 ist. Mir sind TP, FP, FN, TN bekannt, aber ich weiß nicht, wie ich die C-Statistik anhand dieser Informationen berechnen soll.

Antworten:


115

Ich würde Hanleys & McNeils Arbeit von 1982 " Die Bedeutung und Verwendung der Fläche unter einer Empfänger-Betriebskennlinie (ROC) " empfehlen .

Beispiel

Sie haben die folgende Tabelle mit Krankheitsstatus und Testergebnissen (die beispielsweise dem geschätzten Risiko aus einem Logistikmodell entsprechen). Die erste Zahl rechts ist die Anzahl der Patienten mit dem wahren Krankheitsstatus "normal" und die zweite Zahl ist die Anzahl der Patienten mit dem wahren Krankheitsstatus "abnormal":

(1) Auf jeden Fall normal: 33/3
(2) Wahrscheinlich normal: 6/2
(3) Fraglich: 6/2
(4) Wahrscheinlich abnormal: 11/11
(5) Auf jeden Fall abnormal: 2/33

Es gibt also insgesamt 58 "normale" und "51" abnormale Patienten. Wir sehen, dass wenn der Prädiktor 1 ist, "Definitiv normal", der Patient normalerweise normal ist (wahr für 33 der 36 Patienten), und wenn er 5 ist, "Definitiv abnormal", ist der Patient normalerweise abnormal (wahr für 33 der 36 Patienten) 35 Patienten), so macht der Prädiktor Sinn. Aber wie sollen wir einen Patienten mit einer Punktzahl von 2, 3 oder 4 beurteilen? Was wir für die Beurteilung eines Patienten als abnormal oder normal festgelegt haben, um die Empfindlichkeit und Spezifität des resultierenden Tests zu bestimmen.

Sensitivität und Spezifität

Wir können die geschätzte Empfindlichkeit und Spezifität für verschiedene Grenzwerte berechnen . (Ab jetzt schreibe ich nur noch "Sensitivität" und "Spezifität" und lasse die geschätzte Natur der Werte implizit sein.)

Wenn wir unseren Cutoff so wählen, dass wir alle Patienten als abnormal einstufen , unabhängig von den Testergebnissen (dh wir wählen den Cutoff 1+), erhalten wir eine Sensitivität von 51/51 = 1. Die Spezifität ist 0 / 58 = 0. Klingt nicht so gut.

OK, also wählen wir einen weniger strengen Cutoff. Wir stufen Patienten nur dann als abnormal ein, wenn sie ein Testergebnis von 2 oder höher haben. Wir vermissen dann 3 abnormale Patienten und haben eine Empfindlichkeit von 48/51 = 0,94. Wir haben jedoch eine stark erhöhte Spezifität von 33/58 = 0,57.

Nun können wir fortfahren und verschiedene Grenzwerte auswählen (3, 4, 5,> 5). (Im letzten Fall werden keine Patienten als abnormal eingestuft, auch wenn sie die höchstmögliche Testnote von 5 haben.)

Die ROC-Kurve

Wenn wir dies für alle möglichen Grenzwerte tun und die Empfindlichkeit gegen 1 abzüglich der Spezifität grafisch darstellen, erhalten wir die ROC-Kurve. Wir können den folgenden R-Code verwenden:

# Data
norm     = rep(1:5, times=c(33,6,6,11,2))
abnorm   = rep(1:5, times=c(3,2,2,11,33))
testres  = c(abnorm,norm)
truestat = c(rep(1,length(abnorm)), rep(0,length(norm)))

# Summary table (Table I in the paper)
( tab=as.matrix(table(truestat, testres)) )

Die Ausgabe ist:

        testres
truestat  1  2  3  4  5
       0 33  6  6 11  2
       1  3  2  2 11 33

Wir können verschiedene Statistiken berechnen:

( tot=colSums(tab) )                            # Number of patients w/ each test result
( truepos=unname(rev(cumsum(rev(tab[2,])))) )   # Number of true positives
( falsepos=unname(rev(cumsum(rev(tab[1,])))) )  # Number of false positives
( totpos=sum(tab[2,]) )                         # The total number of positives (one number)
( totneg=sum(tab[1,]) )                         # The total number of negatives (one number)
(sens=truepos/totpos)                           # Sensitivity (fraction true positives)
(omspec=falsepos/totneg)                        # 1 − specificity (false positives)
sens=c(sens,0); omspec=c(omspec,0)              # Numbers when we classify all as normal

Und damit können wir die (geschätzte) ROC-Kurve zeichnen:

plot(omspec, sens, type="b", xlim=c(0,1), ylim=c(0,1), lwd=2,
     xlab="1 − specificity", ylab="Sensitivity") # perhaps with xaxs="i"
grid()
abline(0,1, col="red", lty=2)

AUC-Kurve

Manuelle Berechnung der AUC

Wir können die Fläche unter der ROC-Kurve sehr einfach berechnen, indem wir die Formel für die Fläche eines Trapezes verwenden:

height = (sens[-1]+sens[-length(sens)])/2
width = -diff(omspec) # = diff(rev(omspec))
sum(height*width)

Das Ergebnis ist 0.8931711.

Eine Konkordanzmaßnahme

Die AUC kann auch als Konkordanzmaß angesehen werden. Wenn wir alle möglichen nehmen Paare von Patienten , bei denen eine normal ist und das andere ist abnormal, können wir berechnen , wie häufig ist es der anormale derjenige, der die höchste ( die meisten ‚abnormal schau‘) Testergebnis hat (wenn sie den gleichen Wert haben , wir zähle dies als "halben Sieg"):

o = outer(abnorm, norm, "-")
mean((o>0) + .5*(o==0))

Die Antwort ist wieder 0,8931711, die Fläche unter der ROC-Kurve. Dies wird immer der Fall sein.

Eine grafische Ansicht der Konkordanz

Wie Harrell in seiner Antwort hervorhob, hat dies auch eine grafische Interpretation. Zeichnen Sie die Testergebnisse (Risikoschätzung) auf der y- Achse und den wahren Krankheitsstatus auf der x- Achse (hier mit etwas Jittering, um überlappende Punkte anzuzeigen):

plot(jitter(truestat,.2), jitter(testres,.8), las=1,
     xlab="True disease status", ylab="Test score")

Streudiagramm der Risikobewertung gegen den tatsächlichen Krankheitsstatus.

Zeichnen wir nun eine Linie zwischen jedem Punkt auf der linken Seite (ein "normaler" Patient) und jedem Punkt auf der rechten Seite (ein "abnormaler" Patient). Der Anteil der Linien mit einer positiven Steigung (dh der Anteil der Konkordantenpaare ) ist der Konkordanzindex (flache Linien zählen als „50% Konkordanz“).

Es ist ein bisschen schwierig, die tatsächlichen Linien für dieses Beispiel zu visualisieren, da die Anzahl der Verbindungen (gleiche Risikobewertung), aber mit etwas Jitter und Transparenz können wir eine vernünftige Darstellung erhalten:

d = cbind(x_norm=0, x_abnorm=1, expand.grid(y_norm=norm, y_abnorm=abnorm))
library(ggplot2)
ggplot(d, aes(x=x_norm, xend=x_abnorm, y=y_norm, yend=y_abnorm)) +
  geom_segment(colour="#ff000006",
               position=position_jitter(width=0, height=.1)) +
  xlab("True disease status") + ylab("Test\nscore") +
  theme_light()  + theme(axis.title.y=element_text(angle=0))

Streudiagramm der Risikobewertung gegen den tatsächlichen Krankheitsstatus mit Linien zwischen allen möglichen Beobachtungspaaren.

Wir sehen, dass die meisten Linien nach oben geneigt sind, sodass der Konkordanzindex hoch ist. Wir sehen auch den Beitrag zum Index von jeder Art von Beobachtungspaar. Das meiste davon stammt von normalen Patienten mit einem Risikowert von 1, gepaart mit abnormalen Patienten mit einem Risikowert von 5 (1–5 Paare), aber ziemlich viel kommt auch von 1–4 Paaren und 4–5 Paaren. Und es ist sehr einfach, den tatsächlichen Konkordanzindex basierend auf der Steigungsdefinition zu berechnen:

d = transform(d, slope=(y_norm-y_abnorm)/(x_norm-x_abnorm))
mean((d$slope > 0) + .5*(d$slope==0))

Die Antwort ist wieder 0,8931711, dh die AUC.

Der Wilcoxon-Mann-Whitney-Test

Es besteht ein enger Zusammenhang zwischen dem Konkordanzmaß und dem Wilcoxon-Mann-Whitney-Test. Letztere prüft tatsächlich, ob die Wahrscheinlichkeit einer Übereinstimmung (dh, dass es der abnormale Patient in einem zufälligen Normal-Abnormal-Paar ist, der das am „abnormalsten aussehende“ Testergebnis hat) genau 0,5 ist. Und seine Teststatistik ist nur eine einfache Transformation der geschätzten Konkordanzwahrscheinlichkeit:

> ( wi = wilcox.test(abnorm,norm) )
    Wilcoxon rank sum test with continuity correction

data:  abnorm and norm
W = 2642, p-value = 1.944e-13
alternative hypothesis: true location shift is not equal to 0

Die Teststatistik ( W = 2642) zählt die Anzahl der übereinstimmenden Paare. Wenn wir es durch die Anzahl der möglichen Paare teilen, erhalten wir eine vertraute Zahl:

w = wi$statistic
w/(length(abnorm)*length(norm))

Ja, es ist 0,8931711, der Bereich unter der ROC-Kurve.

Einfachere Berechnung der AUC (in R)

Aber machen wir uns das Leben leichter. Es gibt verschiedene Pakete, die die AUC für uns automatisch berechnen.

Das Epi-Paket

Das EpiPaket erstellt eine schöne ROC-Kurve mit verschiedenen eingebetteten Statistiken (einschließlich der AUC):

library(Epi)
ROC(testres, truestat) # also try adding plot="sp"

ROC-Kurve aus dem Epi-Paket

Das pROC-Paket

Ich mag das pROCPaket auch, da es die ROC-Schätzung glätten kann (und eine AUC-Schätzung basierend auf der geglätteten ROC berechnet):

ROC-Kurve (ungeglättet und geglättet) aus dem pROC-Paket

(Die rote Linie ist der ursprüngliche ROC, und die schwarze Linie ist der geglättete ROC. Beachten Sie auch das Standard-Seitenverhältnis von 1: 1. Es ist sinnvoll, dies zu verwenden, da sowohl die Empfindlichkeit als auch die Spezifität einen Bereich von 0 bis 1 haben.)

Die geschätzte AUC aus dem geglätteten ROC beträgt 0,9107, ähnlich der AUC aus dem ungeglätteten ROC, ist jedoch etwas größer (wenn Sie sich die Abbildung ansehen, können Sie leicht erkennen, warum sie größer ist). (Obwohl wir wirklich zu wenige mögliche eindeutige Testergebniswerte haben, um eine glatte AUC zu berechnen).

Das RMS-Paket

Harrells rmsPaket kann mit der rcorr.cens()Funktion verschiedene zugehörige Konkordanzstatistiken berechnen . Das C Indexin seiner Ausgabe ist die AUC:

> library(rms)
> rcorr.cens(testres,truestat)[1]
  C Index 
0.8931711

Das caTools-Paket

Schließlich haben wir das caToolsPaket und seine colAUC()Funktion. Es hat einige Vorteile gegenüber anderen Paketen (hauptsächlich Geschwindigkeit und die Fähigkeit, mit mehrdimensionalen Daten zu arbeiten - siehe ?colAUC), die manchmal hilfreich sein können. Aber es gibt natürlich die gleiche Antwort, die wir immer wieder berechnet haben:

library(caTools)
colAUC(testres, truestat, plotROC=TRUE)
             [,1]
0 vs. 1 0.8931711

ROC-Kurve aus dem caTools-Paket

Letzte Worte

Viele Leute scheinen zu glauben, dass die AUC uns sagt, wie 'gut' ein Test ist. Und einige Leute denken, dass die AUC die Wahrscheinlichkeit ist, dass der Test einen Patienten richtig klassifiziert. Es ist nicht . Wie Sie aus dem obigen Beispiel und Berechnungen sehen können, sagt die AUC uns etwas über eine Familie von Tests, ein Test für jede mögliche Cutoff.

Und die AUC wird basierend auf Grenzwerten berechnet, die man in der Praxis niemals verwenden würde. Warum sollten wir uns für die Empfindlichkeit und Spezifität von "unsinnigen" Grenzwerten interessieren? Dennoch basiert die AUC (teilweise) darauf. (Wenn die AUC sehr nahe bei 1 liegt, hat natürlich fast jeder mögliche Test eine große Unterscheidungskraft, und wir würden uns alle sehr freuen.)

Die "zufällige Normal-Abnormal-Paarinterpretation" der AUC ist nett (und kann zum Beispiel auf Überlebensmodelle ausgedehnt werden, bei denen wir sehen, ob es sich um die Person mit dem höchsten (relativen) Risiko handelt, die am frühesten stirbt). Aber man würde es niemals in der Praxis anwenden. Es ist ein seltener Fall, in dem man weiß, dass man eine gesunde und eine kranke Person hat, nicht weiß, welche Person die kranke ist und entscheiden muss, welche von ihnen zu behandeln ist. (In jedem Fall ist die Entscheidung einfach; behandeln Sie denjenigen mit dem höchsten geschätzten Risiko.)

Daher denke ich, dass das Studieren der tatsächlichen ROC-Kurve nützlicher ist, als nur die AUC-Zusammenfassung zu betrachten. Und wenn Sie die ROC zusammen mit (Schätzungen der) Kosten für falsch-positive und falsch-negative Ergebnisse sowie den Basisraten für das, was Sie studieren, verwenden, können Sie irgendwohin gelangen.

Beachten Sie auch, dass die AUC nur die Diskriminierung und nicht die Kalibrierung misst . Das heißt, es wird gemessen, ob Sie zwei Personen (eine kranke und eine gesunde) anhand der Risikobewertung unterscheiden können. Dabei werden nur relative Risikowerte (oder Ränge, wenn Sie so wollen, vgl. Die Wilcoxon-Mann-Whitney-Testinterpretation) betrachtet, nicht die absoluten, die Sie interessieren sollten . Zum Beispiel, wenn Sie jedes Risiko aufteilen Schätzen Sie aus Ihrem Logistikmodell um 2, erhalten Sie genau die gleiche AUC (und ROC).

Bei der Bewertung eines Risikomodells ist auch die Kalibrierung von großer Bedeutung. Um dies zu untersuchen, werden Sie alle Patienten mit einem Risikowert von etwa 0,7 untersuchen und feststellen, ob ungefähr 70% dieser Patienten tatsächlich krank waren. Tun Sie dies für jede mögliche Risikobewertung (möglicherweise mit einer Art Glättung / lokaler Regression). Zeichnen Sie die Ergebnisse ein und Sie erhalten ein grafisches Kalibrierungsmaß .

Wenn ein Modell mit haben beide Kalibrierung gut und eine gute Unterscheidung, dann starten Sie gutes Modell haben. :)


8
Vielen Dank, @ Karl Ove Hufthammer, das ist die gründlichste Antwort, die ich je erhalten habe. Ich schätze besonders Ihren Abschnitt "Final Words". Ausgezeichnete Arbeit! Danke noch einmal!
Matt Reichenbach

Vielen Dank für diese ausführliche Antwort. Ich arbeite mit einem Datensatz, bei dem Epi :: ROC () v2.2.6 davon überzeugt ist, dass die AUC 1,62 beträgt (nein, es ist keine mentalistische Studie), aber laut ROC glaube ich viel mehr an die 0.56, die der obige Code ergibt in.
BurninLeo

32

Schauen Sie sich diese Frage an: Grundlegendes zur ROC-Kurve

So erstellen Sie eine ROC-Kurve (aus dieser Frage):

ROC-Kurve zeichnen

gegeben einen Datensatz von Ihrem Ranking-Klassifikator verarbeitet

  • Rang Test Beispiele auf abnehmender Punktzahl
  • beginnen in(0,0)
  • für jedes Beispiel (in absteigender Reihenfolge) x
    • Wenn positiv ist, gehe oben1 / posx1/pos
    • wenn negativ ist, gehe rechts1 / negx1/neg

Dabei sind und die Bruchteile von positiven bzw. negativen Beispielen.negposneg

Sie können diese Idee verwenden, um den AUC-ROC mithilfe des folgenden Algorithmus manuell zu berechnen:

auc = 0.0
height = 0.0

for each training example x_i, y_i
  if y_i = 1.0:
    height = height + tpr
  else 
    auc = auc + height * fpr

return auc

Dieses schöne GIF-animierte Bild soll diesen Vorgang deutlicher veranschaulichen

die Kurve bauen


1
Danke @Alexey Grigorev, dies ist ein großartiges Bild und wird sich wahrscheinlich in Zukunft als nützlich erweisen! +1
Matt Reichenbach

1
Könnten Sie bitte etwas über "Bruchteile von positiven und negativen Beispielen" erklären, meinen Sie den kleinsten Einheitswert von zwei Achsen?
Allan Ruin

1
@Allan Ruin: poshier bedeutet die Anzahl der positiven Daten. Nehmen wir an, Sie haben 20 Datenpunkte, in denen 11 Punkte 1 sind. Beim Zeichnen des Diagramms haben wir also ein Rechteck von 11 x 9 (Höhe x Breite). Alexey Grigorev hat skaliert, aber lassen Sie es einfach so, wie es Ihnen gefällt. Bewegen Sie nun bei jedem Schritt 1 auf der Karte.
Catbuilts

5

Karls Post hat eine Menge exzellenter Informationen. Aber ich habe in den letzten 20 Jahren noch kein Beispiel für eine ROC-Kurve gesehen, die das Denken in eine gute Richtung verändert hat. Der einzige Wert einer ROC-Kurve ist meiner bescheidenen Meinung nach, dass ihre Fläche einer sehr nützlichen Konkordanzwahrscheinlichkeit entspricht. Die ROC-Kurve selbst verleitet den Leser dazu, Grenzwerte zu verwenden, was eine schlechte statistische Praxis ist.

Erstellen Sie für die manuelle Berechnung des Index ein Diagramm mit auf der Achse und dem kontinuierlichen Prädiktor oder der vorhergesagten Wahrscheinlichkeit, dass auf der Achse ist. Wenn Sie jeden Punkt mit mit jedem Punkt mit , ist der Anteil der Linien mit einer positiven Steigung die Konkordanzwahrscheinlichkeit.Y = 0 , 1 x Y = 1 y Y = 0 y = 1cY=0,1xY=1yY=0Y=1

Alle Kennzahlen, die in dieser Einstellung einen Nenner von haben, sind Regeln für die fehlerhafte Genauigkeitsbewertung und sollten vermieden werden. Dies schließt den korrekt klassifizierten Anteil, die Sensitivität und die Spezifität ein.n

Drucken Sie für die R- HmiscPaketfunktion rcorr.censdas gesamte Ergebnis aus, um weitere Informationen anzuzeigen, insbesondere einen Standardfehler.


Vielen Dank, @Frank Harell, ich schätze Ihre Perspektive. Ich benutze einfach die c-Statistik als Konkordanzwahrscheinlichkeit, da ich keine Cutoffs mag. Danke noch einmal!
Matt Reichenbach

4

Hier finden Sie eine Alternative zur natürlichen Methode zur Berechnung der AUC, indem Sie einfach die Trapezregel verwenden, um die Fläche unter der ROC-Kurve abzurufen.

Die AUC ist gleich der Wahrscheinlichkeit, dass eine zufällig ausgewählte positive Beobachtung eine vorhergesagte Wahrscheinlichkeit (positiv zu sein) aufweist, die größer ist als eine zufällig ausgewählte negative Beobachtung. Auf diese Weise können Sie die AUC in jeder Programmiersprache ganz einfach berechnen, indem Sie alle paarweisen Kombinationen aus positiven und negativen Beobachtungen durchgehen. Sie können Beobachtungen auch nach dem Zufallsprinzip erfassen, wenn die Stichprobengröße zu groß ist. Wenn Sie die AUC mit Stift und Papier berechnen möchten, ist dies möglicherweise nicht der beste Ansatz, es sei denn, Sie haben eine sehr kleine Stichprobe / viel Zeit. Zum Beispiel in R:

n <- 100L

x1 <- rnorm(n, 2.0, 0.5)
x2 <- rnorm(n, -1.0, 2)
y <- rbinom(n, 1L, plogis(-0.4 + 0.5 * x1 + 0.1 * x2))

mod <- glm(y ~ x1 + x2, "binomial")

probs <- predict(mod, type = "response")

combinations <- expand.grid(positiveProbs = probs[y == 1L], 
        negativeProbs = probs[y == 0L])

mean(combinations$positiveProbs > combinations$negativeProbs)
[1] 0.628723

Wir können mit dem pROCPaket überprüfen :

library(pROC)
auc(y, probs)
Area under the curve: 0.6287

Unter Verwendung der gelegentlichen Stichprobe:

mean(sample(probs[y == 1L], 100000L, TRUE) > sample(probs[y == 0L], 100000L, TRUE))
[1] 0.62896

1
  1. Sie haben den wahren Wert für Beobachtungen.
  2. Berechnen Sie die hintere Wahrscheinlichkeit und ordnen Sie dann die Beobachtungen nach dieser Wahrscheinlichkeit.
  3. PN
    Sum of true ranks0.5PN(PN+1)PN(NPN)

1
@ user73455 ... 1) Ja, ich habe den wahren Wert für Beobachtungen. 2) Ist die hintere Wahrscheinlichkeit gleichbedeutend mit den vorhergesagten Wahrscheinlichkeiten für jede der Beobachtungen? 3) verstanden; Was ist jedoch "Summe der wahren Ränge" und wie berechnet man diesen Wert? Vielleicht hilft Ihnen ein Beispiel, diese Antwort genauer zu erklären? Danke!
Matt Reichenbach
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.