Esimerkki, kun blending parantaa ennustustarkkuutta: Logistisen mallin ennusteet ovat kolmen lainanhakijan maksuhäiriöiden todennäköisyyksistä seuraavat:
Hakija1: 0.09, Hakija2: 0.05, Hakija3: 0.045.
Vastaavat random forestista saadut todennäköisyydet ovat:
Hakija1: 0.08, Hakija2: 0.09, Hakija3: 0.1
Kuvitellaan, että todellisuudessa Hakijat 1 ja 3 saivat maksuhäiriön. Logistinen malli ennusti siis hakijat maksuhäiriön todennäköisyyden mukaisesti suuruusjärjestykseen seuraavasti: Hakija1, Hakija2, Hakija3. Random forestilla vastaava järjestys oli: Hakija3, Hakija2, Hakija1. Oikea järjestys olisi ollut Hakija1, Hakija3, Hakija2, eli hakijoiden 1 ja 3 olisi pitänyt saada suuremmat maksuhäiriön todennäköisyydet kuin toisen hakijan. Yhdistämällä mallit seuraavasti saamme optimaalisen mallin: 0.5* Logistisen mallin ennusteet + 0.5* Random forestin ennusteet. Nyt hakijoiden maksuhäiriöiden todennäköisyydet ovat: Hakija1: 0.085, Hakija2: 0.07, Hakija3: 0.0725. Saimme yhdistämällä mallin, joka on parempi kuin yksittäiset mallit.
Kokeilen seuraavaksi kolmen eri mallin yhdistämistä. Muodostan mallit jo tutusta luottodatasta (GermanCreditData). Malleina käytän logistista regressiota, random forestia ja support vector machinea.
R-koodi:
data <- read.delim(file.choose(), header=FALSE,sep="") # Avataan data ja nimetään muuttujat
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"))
data$amount <- as.factor(ifelse(trainingdata$amount<=2500,"2500",ifelse(data$amount<=5000,'2600-5000','5000+')))
data$duration <- as.factor(ifelse(trainingdata$duration <= 12,"1-12",ifelse(datadata$duration <=24,"13-24","24+")))
data$age <- as.factor(ifelse(testdata$age <= 30,"0-30",ifelse(data$age <=40,"31-40","40+")))
d <- sort(sample(nrow(data),0.6*nrow(data))) # Muodostetaan training- ja testdata
data$amount <- as.factor(ifelse(trainingdata$amount<=2500,"2500",ifelse(data$amount<=5000,'2600-5000','5000+')))
data$duration <- as.factor(ifelse(trainingdata$duration <= 12,"1-12",ifelse(datadata$duration <=24,"13-24","24+")))
data$age <- as.factor(ifelse(testdata$age <= 30,"0-30",ifelse(data$age <=40,"31-40","40+")))
d <- sort(sample(nrow(data),0.6*nrow(data))) # Muodostetaan training- ja testdata
trainingdata <- data[d,]
testdata <- data[-d,]
model1 <- glm(default~check_acc+duration+history+purpose+ # Tehdään logistinen malli
amount+
sav_acc+
employment+
install_rate+
ptatus+
other_debtor+
resid+
property+
age+
other_install+
housing+
other_credits+
job+
num_depend+
teleph+
foreign,family=binomial(link=logit),data=trainingdata)
testdata$log <- predict(model1, testdata,type="response") # Muodostetaan mallin ennusteet
m1.scores <- prediction(testdata$log, testdata$default)
performance(m1.scores,"auc") # AUC 0.773
library(randomForest) # Muodostetaan random forest -malli
model2 <- randomForest(default~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, ntree=1000, data=trainingdata)
testdata$rf <- predict(model2, testdata,type="prob")[,2] # Muodostetaan mallin ennusteet
m2.scores <- prediction(testdata$rf, testdata$default)
performance(m2.scores,"auc") # AUC 0.794
library(kernlab)
model3 <- ksvm(default~check_acc+duration+history+purpose+ # SVM-malli
amount+
sav_acc+
employment+
install_rate+
ptatus+
other_debtor+
resid+
property+
age+
other_install+
housing+
other_credits+
job+
num_depend+
teleph+
foreign, data=trainingdata,
cross=5,type='eps-svr' )
svm <- predict(mode13, testdata,type="response") # Muodostetaan mallin ennusteet
logsvm <- glm(testdata$default~svm,family=binomial) #Huom. SVM ei anna todennäköisyyksiä suoraan, joten ne ratkaistaan erikseen logistisella mallilla.
testdata$svm <- predict(logsvm, testdata,type="response")
m3.scores <- prediction(testdata$svm, testdata$default)
performance(m3.scores,"auc") # AUC 0.778
Random forest ennusti parhaiten testidataan (AUC: 0.794). Kokeillaan parantaako mallien keskiarvottaminen ennusteita.
R-koodi:
preyhd <- (testdata$m1.log+testdata$rf+testdata$svm)/3
m4.scores <- prediction(preyhd, testdata$default)
performance(m4.scores,"auc") # AUC 0.796
R-koodi:
preyhd <- (testdata$m1.log+testdata$rf+testdata$svm)/3
m4.scores <- prediction(preyhd, testdata$default)
performance(m4.scores,"auc") # AUC 0.796
Mallien yhdistäminen paransi hieman AUC-arvoa. Tehtävänä on seuraavaksi löytää optimaaliset painot ennusteille, eli voimme esim. painottaa random forestin ennusteita enemmän. Painojen löytämiseen voi käyttää esim. meta-luokittelijaa, jolloin puhutaan ns. stacking:sta. Tällöin käytämme esim. logistista regressiomallia apuna oikeiden painojen löytämiseen. Idea on laittaa mallien ennusteet mallin selittäviksi tekijöiksi ja muodostaa näiden kertoimista painot.
Esittelen nyt menetelmän, jolla testidatan AUC-arvo voidaan maksimoida. Täytyy tietysti muistaa, ettei tälle testidatalle optimaalisen AUC:n antavat painot välttämättä toimi parhaiten uudelle datalle. Saamme kuitenkin arvokasta tietoa oikeiden painojen suunnasta.
install.packages("Metrics")
library("Metrics")
cols <- c("m1.log","rf","svm")
fn.opt.pred <- function(pars, data) {
pars.m <- matrix(rep(pars,each=nrow(data)),nrow=nrow(data))
rowSums(data*pars.m)
}
fn.opt <- function(pars) {
-auc(testdata$default, fn.opt.pred(pars, testdata[,cols]))
}
pars <- rep(1/length(cols),length(cols))
opt.result <- optim(pars, fn.opt, control = list(trace = T))
test.pred <- fn.opt.pred(opt.result$par, testdata[,cols])
print(opt.result$par)
# Saadaan optimaaliset painot: 0.3890623 0.8060392 0.1767558
Näillä painoilla saamme AUC-arvoksi 0.799. On hyvä huomata, että random forest saa suurimman painon. Random forest oli alunperin malleista ennusteissaan paras, joten parhaalle mallille on luontevaa antaa suurin paino malleja yhdistellessä.
Ei kommentteja:
Lähetä kommentti