ROC curve-wat je altijd al wilde weten maar niet durfde te vragen...


Dit bericht is, zoals vele, geïnspireerd door de vraag van de student. Het blijkt dat velen van ons ROC-curves gebruiken in de analyse zonder echt te weten waarvoor die curves dienen en hoe ze tot stand komen.

De classificatiemodellen zijn een zeer populair hulpmiddel geworden en maken deel uit van veel geïmplementeerde, op grote schaal beschikbare black-box oplossingen, vaak als onderdeel van instrumenten voor machinaal leren. Enerzijds is deze gemakkelijke beschikbaarheid van kant-en-klare hulpmiddelen zeer verleidelijk en stimuleert het mensen om ze te proberen. Anderzijds, omdat het gegeven is, zoekt niemand aanvullende kennis over de methode. Heel vaak ziet men de geïmplementeerde code van dergelijke classificatiemodellen niet. Daarom is het niet duidelijk wat er achter die zwarte doos schuilgaat.

Laten we een voorbeeld nemen uit de geneeskunde. Laten we aannemen dat we een binair 0-1 antwoord hebben, dat aangeeft of een patiënt ziek (1) of gezond (0) is. Daarnaast hebben we enkele gegevens over de patiënten waarvan we denken of weten dat ze mogelijke voorspellers zijn voor de kans om ziek of gezond te zijn, zoals leeftijd, BMI, geslacht of roken. Het model dat onze binaire voorspeller verbindt met de lineaire combinatie van de voorspellers heet het logistisch regressiemodel. Het is de veralgemening van het bekende lineaire normale regressiemodel, maar deze keer is onze respons binair, niet continu, en moeten we deze binaire respons verbinden met het lineaire deel van het model. Dat gebeurt via de zogenaamde linkfunctie, die een logitfunctie is voor het logistische regressiemodel. In R ziet de code om een logistisch regressiemodel te fitten er als volgt uit:

my_model<-glm(binary_response~ age + smoke + bmi + gender,family=binomial, data=my_data))
samenvatting(mijn_model)

Het bovenstaande model kan een definitief model zijn na toepassing van een of andere stapsgewijze opbouwprocedure om de uiteindelijke reeks significante voorspellers te verkrijgen. Of wij willen die voorspellers testen op onze gegevens in de wetenschap dat zij in andere studies significant zijn bevonden.

Wij bouwen modellen om twee redenen:

  1. Om conclusies te trekken. Dan moeten we echt die niet significante predictoren elimineren met bijvoorbeeld een of andere achterwaartse eliminatieprocedure.
  2. Voor de voorspelling. Dan kan het model overrfitted zijn. Het maakt ons niet zoveel uit wat erin zit, zolang het maar een goed voorspellend vermogen heeft.

Laten we ons concentreren op dit tweede doel, want dat is waar de ROC-curve van pas komt. Maar eerst dit. Na het inpassen van het model willen we zien hoe goed de voorspelling van dat model is. Idealiter bouwen/trainen we ons model op de zgn. trainingsset en test het dan op de andere testset. Het kunnen dezelfde gegevens zijn, maar we gebruiken een deel ervan als trainingsdeel en een ander deel als testdeel. De vraag is in welke verhouding we dat moeten doen. Dat is niet triviaal en het is een onderwerp van zgn. kruisvalidatie methoden. Idealiter zouden we verschillende splitsingen moeten onderzoeken en deze procedure herhalen door willekeurig uit onze gegevens te putten. Laten we voor nu aannemen dat we onze proefgegevens hadden die werden gebruikt om een model te bouwen, en dat we nu nieuwe gegevens hebben waarvoor we de prestaties van ons model willen controleren.

Eerst maken we voorspellingen van onze respons uit het gepaste logistische model.

voorspeld<-predict(mijn_model,type=c("antwoord"))

Het is belangrijk te beseffen dat er een waarschijnlijkheid wordt voorspeld, geen binaire respons. Stel dat voor patiënt X de voorspelling 0,7 was. Betekent dat dat hij/zij ziek is? Als we aannemen dat iedereen met een waarschijnlijkheid >0,5 ziek is, dan is hij/zij volgens ons model inderdaad ziek. De keuze van drempel 0,5 is hier cruciaal. Nadat we bijvoorbeeld 0,5 hebben gekozen, kunnen we de prestaties van het model onderzoeken.

predicted.threshold  my_threshold)

Als wij mijn_drempel op 0,5 stellen, zal het antwoord van precited.treshold binair zijn. Het zal 1 zijn voor die waarschijnlijkheden >0.5 en 0 anders. Wij kunnen dan kijken naar de verwarringsmatrix.

table(my_data$binary_response,predicted.threshold)

voorspelde.drempel
    
      0 1
  0 25 304
  1 13 258

Uit die verwarringmatrix kunnen we opmaken hoeveel fout-positief (FP) waarnemingen die we hebben, die door het model als ziek (1) worden voorspeld, maar die gezond zijn. Bovendien hebben we vals negatief (FN) waarnemingen, die als gezond worden voorspeld, maar in feite ziek zijn. De rest van de waarnemingen zal ware positieven (TP), correct voorspeld als ziek en echte negatieven (TN)correct voorspeld als gezond.

De gebruikelijke maatstaf om de modelprestaties te beoordelen is gevoeligheid=TP/PDit is het percentage van alle zieke patiënten (P) dat als ziek wordt gedetecteerd. Een tweede maatstaf is de zogenaamde specificiteit=TN/Ndat is het deel van alle gezonde patiënten dat als gezond wordt gedetecteerd.

Niemand zegt ons dat onze drempel 0,5 moet zijn. Waarom niet 0,6? Als we de drempel veranderen, veranderen de voorspellingen, verandert de verwarringsmatrix en veranderen de gevoeligheid en specificiteit.

Hoe kies je deze drempel om de specificiteit en gevoeligheid te maximaliseren? Het idee is om beide hoog te hebben. Maar als de gevoeligheid stijgt, daalt de specificiteit en omgekeerd. Het is een afweging tussen deze twee.

Dus moeten we de code uitvoeren voor al die mogelijke drempels? Nee, dat doet de ROC-curve voor ons.

bibliotheek(pROC)

myROC<- roc(my_data$binary_response ~ predicted)

plot(myROC)

In de praktijk krijgen we misschien zoiets als de zwarte ROC-curve, net iets beter dan een willekeurige classificator. Hoe dichter bij de linkerbovenhoek de ROC is, hoe beter, omdat we dan dichter bij de maximale specificiteit=1 en maximale gevoeligheid=1 zitten.

De volgende vraag is hoe de drempel te kiezen. De populairste methode is het kiezen van de drempel die de afstand tot de linkerbovenhoek maximaliseert. Dit kan automatisch worden gedaan door R, maar het is goed om het een keer zelf te programmeren.

topleft<-(1-myROC$gevoeligheden)^2+(1-myROC$specificiteiten)^2
topleft.threshold<-die(topleft==min(topleft))
text(x=myROC$specificities[topleft.threshold], y=myROC$sensitivities[topleft.threshold],"(0.50,0.58)",col=2)

Zodra we dat optimale punt hebben gevonden, kunnen we het met behulp van de tekstfunctie op de grafiek zetten. Op dat punt stopt men gewoonlijk en rapporteert men uiteindelijk AUC (area under the curve) als het totale voorspellende vermogen van het model. Maar we moeten hier niet stoppen. Wij willen uitzoeken welke drempelwaarde (het afkappunt) overeenkomt met het optimale gevoeligheids- en specificiteitspunt.


# voor een bepaalde gevoeligheid en specificiteit
idx.which<-which((myROC$specificities==0.50)&(myROC$sensitivities==0.58))

1TP4Nu nemen we drempelwaarde
myROC$thresholds[idx.which]

predict.treshold  myROC$thresholds[idx.which])
#confusion matrix
table(my_data$binary_response,predict.threshold)

Nu hebben we de optimale drempelwaarde myROC$thresholds[idx.which] gevonden en kunnen we die gebruiken om onze voorspelde kansen te verlagen.

Zoals ik al zei, wordt de oppervlakte onder de ROC-curve gewoonlijk gebruikt als het criterium om het algemene voorspellingsvermogen van ons model samen te vatten. Het is goed te beseffen dat het vermogen over alle mogelijke drempels. Hoe dichter bij 1, hoe beter. De AUC voor de willekeurige classificator is gelijk aan 0,5, wat overeenkomt met het gebied onder de diagonale lijn in de bovenstaande grafiek.

De classificatiemodellen zijn natuurlijk een veel grotere familie dan alleen de logistische regressiemodellen. Het is een breed onderwerp van onderzoek. Het is goed te weten dat er andere methoden zijn, naast de "linksboven"-hoek om het optimale criterium te kiezen, zoals dat van Jouden. Dit criterium behandelt gevoeligheid en specificiteit even belangrijk. Maar dit is niet altijd het geval. Men moet kijken naar de specifieke gegevens in kwestie omdat uw instelling kan heel anders zijn dan die in de handleiding van iemand anders. Terugkomend op het medische voorbeeld. Als uw ziekte kanker is, maakt u zich meer zorgen over de fout-negatieve waarnemingen dan over de fout-positieve. Die fout-positieven zullen verder gediagnosticeerd worden, maar het missen van sommige kankerpatiënten kan hun dood veroorzaken. In dat geval maximaliseer je liever de gevoeligheid ten koste van de specificiteit. Anderzijds, als uw ziekte een HIV is, bent u waarschijnlijk even bezorgd over beide, vals negatieve en vals positieve patiënten.

Veel succes met je modellen!

Dit bericht is geplaatst in Blog. Maak een bladwijzer van de permalink .

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *

nl_NLDutch