lauantai 30. huhtikuuta 2016

Mallin ennustuskyvyn arviointi: Ristiinvalidointi

Kun teemme mallin, jolla haluamme ennustaa, niin on tärkeää arvioida mallin ennustuskykyä etukäteen. Tämä johtuu siitä, että mallit yleensä ylisovittuvat dataan, jolla ne luodaan, eli niiden ennustuskyky ei olekaan enää hyvä uudella datalla. Tämän ongelman ratkaisuksi on keksitty erilaisia ristiinvalidointimenetelmiä, joista esittelen K-ositus -ristiinvalidoinnin (K-fold cross-validation). Menetelmän avulla saamme mallin ennustuskyvystä vakaamman kuvan kuin, jos käyttäisimme perinteistä trainingset ja testset -jakoa. Ristiinvalidointi on erityisen tärkeää, kun datan määrä on pieni, koska tällöin saamme äärimmäisiä tuloksia todennäköisemmin.

K-ositus ristiinvalidoinnin vaiheet:

1. Jaa data k:hon samansuuruiseen osaan. Esim. kun k=3, niin data jaetaan kolmeen samansuureiseen osaan.
2. Muodosta malli käyttäen k-1 osia (trainingset) ja ennusta sillä puuttuvan osan (testset) arvot. Toista tämä, kunnes jokainen osa on ollut kerran testsettinä.
3. Laske kunkin mallin testsetille tuottamien AUC-arvojen keskiarvo.


Esimerkki, kun k=3 ja osat ovat osa1, osa2 ja osa3. Muodostetaan ensin mallit:

Malli 1: Trainingset: osa1 ja osa2. Testset: osa3.
Malli 2: Trainingset: osa1 ja osa3. Testset: osa2.
Malli 3: Trainingset: osa2 ja osa3. Testset: Osa1.

Seuraavaksi malleilla ennustetaan testsetteihin ja saaduista AUC-arvoista lasketaan keskiarvot. Jos saamme esim. AUC-arvot 0.82, 0.78 ja 0.76, niin keskiarvo on ~0.787. Ristiinvalidoinnin tärkeys tulee ilmi tässä kohtaa, koska ilman sitä olisimme voineet päätyä Malli 1:n antamaan AUC-arvoon (0.82), joka antaa liian positiivisen kuvan mallin ennustustarkkuudesta. Ristiinvalidointi antaa siis vakaamman kuvan mallin ennustustarkkuudesta. Esimerkissä k oli kolme, mutta se voi olla myös esim. kymmenen. Lisäämällä k:n arvoa voimme pienentää ristiinvalidoinnista saamaamme AUC-arvon varianssia. Varianssia saadaan myös pienemmäksi, kun ristiinvalidointi suoritetaan useampaan kertaan ja kunkin ristiinvalidoinnin saadut AUC-arvot keskiarvoistetaan. Voimme esim. suorittaa k=10 ristiinvalidoinnin viisi kertaa, jolloin saamamme lopputulos olisi viiden ristiinvalidoinnin tuottaman AUC-arvon keskiarvo.

Tarkastellaan seuraavaksi aiemmin käyttämäämme luottadataa (data) ristiinvalidoinnin näkökulmasta. Lasken mallille ensin AUC-arvon, kun käytämme 60% trainingset ja 40% testset jakoa.


data <- read.delim(file.choose(), header=FALSE,sep="")
names(data) <- c("check_acc", "duration", "history", "purpose", "amount", "sav_acc", "employment", "install_rate", "ptatus", "other_debtor", "resid", "property","age", "other_install", "housing", "other_credits", "job", "num_depend", "teleph", "foreign", "default")
data$install_rate <- as.factor(data$install_rate)
data$resid <- as.factor(data$resid)
data$other_credits <- as.factor(data$other_credits)
data$num_depend <- as.factor(data$num_depend)
data$default <- as.factor(ifelse(data$default==1,"0","1"))

trainingdata$age <- as.factor(ifelse(trainingdata$age <= 30,"0-30",ifelse(trainingdata$age <=40,"31-40","40+")))
trainingdata$amount <-as.factor(ifelse(trainingdata$amount<=2500,"2500",ifelse(trainingdata$amount<=5000,'2600-5000','5000+')))
trainingdata$duration <- as.factor(ifelse(trainingdata$duration <= 12,"1-12",ifelse(trainingdata$duration <=24,"13-24","24+")))

d <- sort(sample(nrow(data),0.6*nrow(data)))
trainingdata <- data[d,]
testdata <- data[-d,]

model1 <- glm(default~.,family=binomial(link=logit),data=trainingdata)
testdata$log <- predict(model1, testdata, type = "response")
f<- prediction(testdata$log,testdata$default)
performance(f,"auc") # AUC-arvo: 0.791

library(ggplot2)
library(plotROC)
plot <- ggplot(testdata,aes(d=default,m=log))+geom_roc()+style_roc()
plot



Saimme AUC-arvoksi 0.791, mutta onko tämä AUC-arvo sellainen, jonka voimme odottaa saavamme myös jatkossa? Tietysti on mahdollista saada kyseinen arvo myös jatkossa, mutta ristiinvalidoinnin avulla saamme parempaa tietoa AUC-arvon odotusarvosta, eli voimme karsia epävarmuutta. Seuraavaksi teen ristiinvalidoinnin, kun k=5.
R-koodi:

library(caret)
d <- createFolds(data$default, k = 5, list = TRUE, returnTrain = FALSE) # Jaetaan data viiteen osaan
names(d)[c(1,2,3,4,5)] <- c("t1","t2","t3","t4","t5") 

m1 <- glm(default~., family=binomial, data=data[c(d$t1,d$t2,d$t3,d$t4),])
g <- predict(m1,data[d$t5,],type="response")
pre1 <- prediction(g,data[d$t5,"default"])
a1 <- performance(pre1,"auc") # AUC: 0.824

m2 <- glm(default~., family=binomial, data[c(d$t1,d$t2,d$t3,d$t5),])
g <- predict(m2,data[d$t4,],type="response")
pre2 <- prediction(g,data[d$t4,"default"])
b1 <- performance(pre2,"auc") # AUC: 0.721

m3 <- glm(default~., family=binomial, data[c(d$t1,d$t2,d$t4,d$t5),])
g <- predict(m3,data[d$t3,],type="response")
pre3 <- prediction(g,data[d$t3,"default"])
c1 <- performance(pre3,"auc") # AUC: 0.801

m4 <- glm(default~., family=binomial, data[c(d$t1,d$t3,d$t4,d$t5),])
g <- predict(m4,data[d$t2,],type="response")
pre4 <- prediction(g,data[d$t2,"default"])
d1 <- performance(pre4,"auc") # AUC: 0.808


m5 <- glm(default~., family=binomial, data[c(d$t2,d$t3,d$t4,d$t5),])
g <- predict(m5,data[d$t1,],type="response")
pre5 <- prediction(g,data[d$t1,"default"])
e1 <- performance(pre5,"auc") # AUC: 0.733


(as.numeric(a1@y.values)+as.numeric(b1@y.values) # Lasketaan keskiarvo
+as.numeric(c1@y.values)+as.numeric(d1@y.values)+as.numeric(e1@y.values))/5

Keskiarvoksi saadaan 0.778, joten näyttää siltä, että ristiinvalidointi paljasti, ettei malli ollutkaan niin hyvä kuin aluksi vaikutti. Kun katsomme saatuja AUC-arvoja, niin huomaamme, kuinka paljon ne vaihtelevat välillä 0.72-0.80. Tämä vaihtelu johtuu datan pienestä koosta (1000 havaintoa). Toistan seuraavaksi ristiinvalidoinnin viisi kertaa ja lasken saatujen arvojen keskiarvon. Arvojen keskiarvoksi saadaan 0.773 ja arvojen vaihteluväli on 0.764-0.777, eli arvojen hajonta on huomattavasti pienempi. Voimme siis päätellä, että mallin ennustukset uudella datalla tuottavat noin 0.77 suuruisen AUC-arvon.




Ei kommentteja:

Lähetä kommentti