I er interessert i å beregne arealet under kurven (AUC), eller c-statistikken, for hånd for en binær logistisk regresjonsmodell.
For eksempel i valideringsdatasettet, jeg har den sanne verdien for den avhengige variabelen, retensjon (1 = beholdt; 0 = ikke beholdt), samt en forventet retensjonsstatus for hver observasjon generert av min regresjonsanalyse ved hjelp av en modell som ble bygget ved hjelp av treningen sett (dette vil variere fra 0 til 1).
Mine første tanker var å identifisere det «riktige» antall modellklassifiseringer og bare dele antall «riktige» observasjoner med antall totale observasjoner å beregne c-statistikken. Ved «korrekt», hvis den sanne retensjonsstatusen til en observasjon = 1 og den forutsagte retensjonsstatusen er> 0,5, er det en «riktig» klassifisering. I tillegg, hvis den sanne retensjonsstatusen til en observasjon = 0 og den forutsagte retensjonsstatusen er < 0,5, er det også en «riktig» klassifisering. Jeg antar at en «tie» ville oppstå når den forutsagte verdien = 0,5, men det fenomenet forekommer ikke i valideringsdatasettet mitt. På den annen side vil «uriktige» klassifiseringer være hvis den sanne retensjonsstatusen til en observasjon = 1 og den forventede retensjonsstatusen er < 0,5 eller hvis den sanne retensjonsstatusen for et resultat = 0 og den forventede retensjonsstatusen er> 0,5. Jeg er klar over TP, FP, FN, TN, men er ikke klar over hvordan jeg skal beregne c-statistikken gitt denne informasjonen.
Svar
Jeg vil anbefale Hanleys & McNeils 1982-papir Betydningen og bruken av området under en mottakeroperasjonskarakteristikk (ROC ) kurve .
Eksempel
De har følgende tabell over sykdomsstatus og testresultat (tilsvarer for eksempel estimert risiko fra en logistisk modell). Det første tallet til høyre er antall pasienter med sann sykdomsstatus normal og det andre tallet er antall pasienter med sann sykdomsstatus unormal:
(1) Definitivt normal: 33/3
(2) Sannsynligvis normal: 6/2
(3) Tvilsom: 6/2
(4) Sannsynligvis unormal: 11/11
(5) Definitivt unormal: 2/33
Så det er totalt 58 normale pasienter og 51 unormale. Vi ser at når prediktoren er 1, «Definitivt normal», er pasienten vanligvis normal (sant for 33 av de 36 pasientene), og når det er 5, «Definitivt unormal» er pasientene vanligvis unormale (sant for 33 av de 35 pasienter), så prediktoren gir mening. Men hvordan skal vi bedømme en pasient med poengsummen 2, 3 eller 4? Det vi setter avskjæringen for å bedømme pasienter som unormal eller normal for å bestemme følsomheten og spesifisiteten til den resulterende testen.
Sensitivitet og spesifisitet
Vi kan beregne estimert følsomhet og spesifisitet for forskjellige avskjæringer. (Jeg skriver bare «sensitivitet» og «spesifisitet» fra nå av, slik at den estimerte naturen til verdiene kan være implisitt.)
Hvis vi velger avskjæringen vår slik at vi klassifiserer alle pasientene som unormale, uansett hva testresultatene deres sier (dvs. vi velger cutoff 1+), vil vi få en følsomhet på 51/51 = 1. Spesifisiteten vil være 0/58 = 0. Gjør ikke høres så bra ut.
OK, så la oss velge en mindre streng avskjæring. Vi klassifiserer pasienter bare som unormale hvis de har et testresultat på 2 eller høyere. Vi savner da 3 unormale pasienter, og har en følsomhet på 48/51 = 0,94. Men vi har en mye økt spesifisitet, på 33/58 = 0,57.
Vi kan nå fortsette dette ved å velge forskjellige cutoffs (3, 4, 5,> 5). (I det siste tilfellet vil vi ikke klassifisere noen pasienter som unormale, selv om de har høyest mulig testpoeng på 5.)
ROC-kurven
Hvis vi gjør dette for alle mulige avskjæringer, og plottet følsomheten mot 1 minus spesifisiteten, får vi ROC-kurven. Vi kan bruke følgende R-kode:
# 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)) )
Utgangen er:
testres truestat 1 2 3 4 5 0 33 6 6 11 2 1 3 2 2 11 33
Vi kan beregne ulike statistikker:
( 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
Og ved å bruke dette kan vi plotte den (estimerte) ROC-kurven:
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)
Manuelt beregne AUC
Vi kan veldig enkelt beregne arealet under ROC-kurven, ved å bruke formelen for arealet til en trapes:
height = (sens[-1]+sens[-length(sens)])/2 width = -diff(omspec) # = diff(rev(omspec)) sum(height*width)
Resultatet er 0.8931711.
Et samstemmende mål
AUC kan også sees på som et samstemmende mål.Hvis vi tar alle mulige par pasienter der den ene er normal og den andre er unormal, kan vi beregne hvor ofte det er den unormale som har det høyeste (mest unormale utseende) testresultatet (hvis de har samme verdi, vi teller at dette som en halv seier):
o = outer(abnorm, norm, "-") mean((o>0) + .5*(o==0))
Svaret er igjen 0.8931711, området under ROC-kurven. Dette vil alltid være tilfelle.
Et grafisk syn på samstemthet
Som påpekt av Harrell i hans svar, har dette også en grafisk tolkning. La oss plotte testpoeng (risikovurdering) på y -aksien og den virkelige sykdomsstatusen på x -aksen (her med litt rystelse, for å vise overlappende punkter):
plot(jitter(truestat,.2), jitter(testres,.8), las=1, xlab="True disease status", ylab="Test score")
La oss nå trekke en linje mellom hvert punkt til venstre (en normal pasient) og hvert punkt til høyre (en unormal pasient). Andelen linjer med en positiv skråning (dvs. andelen samstemmende par) er konkordansindeksen (flate linjer teller som ‘50% samsvar).
Det er litt vanskelig å visualisere de faktiske linjene for dette eksemplet, på grunn av antall bånd (lik risikoscore), men med litt rystelser og gjennomsiktighet kan vi få et rimelig plott:
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))
Vi ser at de fleste linjene skråner oppover, slik at konkordansindeksen vil være høy. Vi ser også bidraget til indeksen fra hver type observasjonspar. Det meste kommer fra normale pasienter med en risikoscore på 1 parret med unormale pasienter med en risikoscore på 5 (1–5 par), men ganske mye kommer også fra 1–4 par og 4–5 par. Og det er veldig enkelt å beregne den faktiske konkordansindeksen basert på skråningsdefinisjonen:
d = transform(d, slope=(y_norm-y_abnorm)/(x_norm-x_abnorm)) mean((d$slope > 0) + .5*(d$slope==0))
Svaret er igjen 0.8931711, dvs. AUC.
Wilcoxon – Mann – Whitney-testen
Det er en nær sammenheng mellom samsvarstiltaket og Wilcoxon – Mann – Whitney test. Faktisk tester sistnevnte om sannsynligheten for samsvar (dvs. at det er den unormale pasienten i et tilfeldig normalt – unormalt par som vil ha det mest unormale utseende testresultatet) er nøyaktig 0,5. Og dens teststatistikk er bare en enkel transformasjon av den estimerte samstemmende sannsynligheten:
> ( 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
Teststatistikken (W = 2642
) teller antall samsvarende par. Hvis vi deler det med antall mulige par, får vi et kjent nummer:
w = wi$statistic w/(length(abnorm)*length(norm))
Ja, det er 0.8931711, området under ROC-kurven.
Enklere måter å beregne AUC (i R)
Men la oss gjøre livet lettere for oss selv. Det er forskjellige pakker som beregner AUC for oss automatisk.
Epi-pakken
Epi
-pakken skaper en fin ROC-kurve med forskjellige statistikk (inkludert AUC) innebygd:
library(Epi) ROC(testres, truestat) # also try adding plot="sp"
pROC-pakken
Jeg liker også pROC
-pakken, siden den kan jevne ROC-estimatet (og beregne et AUC-estimat basert på det glattede ROC):
(Den røde linjen er den opprinnelige ROC, og den svarte linjen er den utjevnede ROC. Vær også oppmerksom på standardformatet 1: 1. Det er fornuftig å bruke dette, siden både følsomhet og spesifisitet har 0–1 .)
Den estimerte AUC fra glatt ROC er 0,9107, lik, men litt større enn, AUC fra den ujevnte ROC (hvis du ser en t figuren, kan du enkelt se hvorfor den er større). (Selv om vi virkelig har for få mulige forskjellige testresultatverdier for å beregne en jevn AUC).
rms-pakken
Harrells rms
-pakke kan beregne forskjellige relaterte samsvarsstatistikker ved hjelp av rcorr.cens()
-funksjonen. C Index
i utgangen er AUC:
> library(rms) > rcorr.cens(testres,truestat)[1] C Index 0.8931711
CaTools-pakken
Til slutt har vi caTools
-pakken og dens colAUC()
-funksjon. Det har noen fordeler i forhold til andre pakker (hovedsakelig hastighet og muligheten til å jobbe med flerdimensjonale data – se ?colAUC
) som kan noen ganger være nyttige.Men det gir selvfølgelig det samme svaret som vi har beregnet om og om igjen:
library(caTools) colAUC(testres, truestat, plotROC=TRUE) [,1] 0 vs. 1 0.8931711
Avsluttende ord
Mange ser ut til å tro at AUC forteller oss hvor bra en test er. Og noen mennesker tror at AUC er sannsynligheten for at testen vil klassifisere en pasient riktig. Det er ikke . Som du kan se fra eksemplet og beregningene ovenfor, forteller AUC oss noe om en familie av tester, en test for hver mulig avskjæring.
Og AUC beregnes basert på avskjæringer man aldri vil bruke i praksis. Hvorfor skal vi bry oss om følsomheten og spesifisiteten til ‘tullløse’ grenseverdier? Likevel er det AUC er (delvis) basert på. (Selvfølgelig, hvis AUC er veldig nær 1, vil nesten alle mulige tester ha stor diskriminerende kraft, og vi vil alle være veldig glade.)
Den tilfeldige normale –Abnormal parfortolkning av AUC er fin (og kan utvides, for eksempel til å overleve modeller, hvor vi ser om det er personen med den høyeste (relative) faren som dør tidligst). Men man vil aldri bruke det i praksis. Det er et sjeldent tilfelle der man vet man har en sunn og en syk person, ikke vet hvilken person som er syk og må bestem hvilken av dem du skal behandle. (Uansett er avgjørelsen enkel; behandle den med høyest estimert risiko.)
Så jeg tror å studere den faktiske ROC-kurven vil være mer nyttig enn bare å se på AUC-sammendragstiltaket. Og hvis du bruker ROC sammen med (estimater av) kostnadene for falske positive og falske negativer, sammen med basisrater for det du studerer, kan du komme deg et sted.
Vær også oppmerksom på at AUC bare måler diskriminering , ikke kalibrering. Det vil si at den måler om du kan skille mellom to personer (en syk og en sunn), basert på risikoscore. For dette ser det bare på relative risikoverdier (eller rangerer, hvis du vil, jf. Wilcoxon – Mann – Whitney-tolkningen), ikke de absolutte som du burde være interessert i. Hvis du for eksempel deler hvert risikostimat fra din logistikkmodell med 2, får du nøyaktig samme AUC (og ROC).
Når du vurderer en risikomodell, kalibrering er også veldig viktig. For å undersøke dette vil du se på alle pasienter med en risikoscore på rundt, f.eks. 0,7, og se om omtrent 70% av disse faktisk var syke. Gjør dette for hver mulig risikoscore (muligens ved hjelp av en slags utjevning / lokal regresjon). Plott resultatene, så får du et grafisk mål på kalibrering .
Hvis du har en modell med både god kalibrering og god diskriminering, så begynner å ha god modell. 🙂
Kommentarer
Svar
Ta en titt på dette spørsmålet: Forstå ROC-kurve
Slik bygger du en ROC-kurve (fra det spørsmålet):
Tegning av ROC-kurve
gitt et datasett behandlet av rangeringsklassifikator
- rangtesteksempler på synkende poengsum
- starter i $ (0, 0) $
- for hvert eksempel $ x $ (i avtagende rekkefølge)
- hvis $ x $ er positiv, flytt $ 1 / \ text {pos} $ opp
- hvis $ x $ er negativ, flytt $ 1 / \ text {neg} $ høyre
hvor $ \ text {pos} $ og $ \ text {neg} $ er brøkene av henholdsvis positive og negative eksempler.
Du kan bruke denne ideen til manuell beregning av AUC ROC ved hjelp av følgende algoritme:
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
Dette fine gif-animerte bildet skal illustrere dette prosessrensere
Kommentarer
- Takk @Alexey Grigorev, dette er en flott visuell og det vil sannsynligvis vise seg å være nyttig i fremtiden! +1
- Kan du forklare litt om » brøker av positive og negative eksempler «, mener du minste enhetsverdi på to akser?
- @Allan Ruin:
pos
betyr her antall positive data. La oss si at du har 20 datapunkter, hvor 11 poeng er 1. Så når vi tegner diagrammet, har vi et rektangel 11×9 (høyde x bredde). Alexey Grigorev gjorde målestokk, men bare la det være som det ‘ hvis du vil. Nå er det bare å flytte 1 på diagrammet ved hvert trinn.
Svar
Karls innlegg har mye med utmerket informasjon. Men jeg har ennå ikke sett de siste 20 årene et eksempel på en ROC-kurve som endret noen som tenkte i en god retning. Den eneste verdien av en ROC-kurve etter min ydmyke oppfatning er at arealet tilfeldigvis tilsvarer en veldig nyttig samsvarssannsynlighet. ROC-kurven frister leseren til å bruke cutoffs, noe som er dårlig statistisk praksis.
Når det gjelder manuell beregning av $ c $ -indeksen, må du lage et plot med $ Y = 0,1 $ på $ x $ -aksis og den kontinuerlige prediktoren eller antatt sannsynlighet for at $ Y = 1 $ på $ y $ -aksien. Hvis du kobler hvert punkt med $ Y = 0 $ til hvert punkt med $ Y = 1 $, er andelen av linjene som har en positiv helling, samsvarssannsynligheten.
Eventuelle mål som har en nevner på $ n $ i denne innstillingen er upassende regler for nøyaktighetsscoring og bør unngås. Dette inkluderer proporsjoner klassifisert riktig, følsomhet og spesifisitet.
For R Hmisc
-pakke rcorr.cens
-funksjonen, skriv ut hele resultatet for å se mer informasjon, spesielt en standardfeil.
Kommentarer
- Takk, @Frank Harell, jeg setter pris på perspektivet ditt. Jeg bruker ganske enkelt c-statistikken som en konkordanssannsynlighet, da jeg ikke ‘ ikke liker avskjæringer. Takk igjen!
Svar
Her er et alternativ til den naturlige måten å beregne AUC ved å bare bruke den trapesformede regelen for å få området under ROC-kurven.
AUC er lik sannsynligheten for at en tilfeldig samplet positiv observasjon har en forutsagt sannsynlighet (for å være positiv) større enn en tilfeldig samplet negativ observasjon. Du kan bruke dette til å beregne AUC ganske enkelt i ethvert programmeringsspråk ved å gå gjennom alle parvise kombinasjoner av positive og negative observasjoner. Du kan også prøve ut observasjoner tilfeldig hvis utvalgsstørrelsen var for stor. Hvis du vil beregne AUC ved bruk av penn og papir, er dette kanskje ikke den beste tilnærmingen med mindre du har en veldig liten prøve / mye tid. For eksempel i 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
Vi kan verifisere ved hjelp av pROC
-pakken:
library(pROC) auc(y, probs) Area under the curve: 0.6287
Bruk av tilfeldig prøvetaking:
mean(sample(probs[y == 1L], 100000L, TRUE) > sample(probs[y == 0L], 100000L, TRUE)) [1] 0.62896
Svar
- Du har virkelig verdi for observasjoner.
- Beregn bakre sannsynlighet og rangér deretter observasjoner etter denne sannsynligheten.
- Forutsatt sannsynlighet for $ P $ og antall observasjoner $ N $:
$$ \ frac {\ text {Sum av sanne ranger} -0.5PN (PN + 1)} { PN (N-PN)} $$
Kommentarer
- @ user73455 … 1) Ja, jeg har den sanne verdien for observasjoner. 2) Er posterior sannsynlighet synonymt med forutsagte sannsynligheter for hver av observasjonene? 3) forstått; hva er imidlertid » Summen av sanne rangeringer » og hvordan beregner man denne verdien? Kanskje et eksempel kan hjelpe deg med å forklare dette svaret grundigere? Takk!
sens=c(sens,0); omspec=c(omspec,0)
, skal ikke ‘ t dette væresens=c(0, sens); omspec=c(0, omspec)
? Den plotter riktig med den ledende0
men ikke slik den er i svaret.sens
ogomspec
før de tegnet).