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)  

AUC-kurve

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")  

Spred plott av risikoscore mot sann sykdom status.

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))  

Spred plott av risikoscore mot ekte sykdomsstatus, med linjer mellom alle mulige observasjonspar.

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"  

ROC-kurve fra Epi-pakken

pROC-pakken

Jeg liker også pROC -pakken, siden den kan jevne ROC-estimatet (og beregne et AUC-estimat basert på det glattede ROC):

ROC-kurve (glatt og glattet) fra pROC-pakken

(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  

ROC-kurve fra caTools-pakken

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

  • Takk, @Karl Ove Hufthammer, dette er det grundigste svaret jeg noen gang har fått. Jeg setter spesielt pris på » Avsluttende ord » -delen. Fantastisk arbeid! Takk igjen!
  • Tusen takk for dette detaljerte svaret. Jeg jobber med et datasett der Epi :: ROC () v2.2.6 er overbevist om at AUC er 1.62 (nei det er ikke en mentalistisk studie), men ifølge ROC tror jeg mye mer på 0.56 som ovennevnte kode resulterer i i.
  • Jeg tror det er en liten feil i sens=c(sens,0); omspec=c(omspec,0), skal ikke ‘ t dette være sens=c(0, sens); omspec=c(0, omspec)? Den plotter riktig med den ledende 0 men ikke slik den er i svaret.
  • Nei, den nåværende definisjonen er, AFAICS, riktig, @steveb, og resulterer i en korrekt plott. Jeg tror det som kanskje er forvirrende er at ROC-kurven er tegnet fra høyre til venstre (dvs. fra øverste høyre hjørne til nederste venstre hjørne), ikke fra venstre til rett , som de fleste tomter er. Det er bare resultatet av hvordan jeg definerte variablene; man kunne like godt ha plottet den fra venstre til høyre (ved å reversere både sens og omspec før de tegnet).

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

bygging av kurven

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

  1. Du har virkelig verdi for observasjoner.
  2. Beregn bakre sannsynlighet og rangér deretter observasjoner etter denne sannsynligheten.
  3. 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!

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *