0. 데이터 탐색

library(ISLR)
head(Default)
str(Default)
## 'data.frame':    10000 obs. of  4 variables:
##  $ default: Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 1 1 1 1 ...
##  $ student: Factor w/ 2 levels "No","Yes": 1 2 1 1 1 2 1 2 1 1 ...
##  $ balance: num  730 817 1074 529 786 ...
##  $ income : num  44362 12106 31767 35704 38463 ...
dim(Default)
## [1] 10000     4
sum(is.na(Default))
## [1] 0

데이터 구조를 확인하였다. 총 변수 4개이고 각 변수당 10000개 관측치를 가진다. 변수 이름은 각각 default, student, balance, income으로 되어있고, 결측값은 존재하지 않았다. Predictor로 사용할 변수가 student, balance, income이고 response variable로 default를 사용한다. 여기서 중요한 것은 predictor 중에서 student(이산형, discrete variable)이고 나머지 balance, income(연속형, continuous variable)이 섞여있다는 점이다.

attach(Default)
library(nortest)
ad.test(balance)
## 
##  Anderson-Darling normality test
## 
## data:  balance
## A = 16.817, p-value < 2.2e-16
ad.test(income)
## 
##  Anderson-Darling normality test
## 
## data:  income
## A = 78.846, p-value < 2.2e-16
hist(balance)

hist(income)

library(lawstat)
## Loading required package: Kendall
## Loading required package: mvtnorm
## Loading required package: VGAM
## Loading required package: stats4
## Loading required package: splines
levene.test(income, income)
## 
##  modified robust Brown-Forsythe Levene-type test based on the
##  absolute deviations from the median
## 
## data:  income
## Test Statistic = NaN, p-value = NA

문제

1. Construct a Bayes’ classifier to predict “default” using “balance” and “income” variables. Estimate the test error rate using (1) VS approach, (2) LOOCV, and (3) 10-fold CV.

n=dim(Default)[1]
set.seed(20144607)
train<-sample(1:n,n/2)
default.train<-Default[train,]
default.test<-Default[-train,]
# VS approach
library(MASS)
nl<-nlevels(default.train[,1])

mu<-list()
S<-list()
pro<-list()
for (i in 1:nl){
    mu[[i]]<-apply(default.train[default.train$default==levels(default.train[,1])[i],3:4],2,mean)
    S[[i]]<-cov(default.train[default.train$default==levels(default.train[,1])[i],3:4])
    pro[[i]]<-dim(default.train[default.train$default==levels(default.train[,1])[i],3:4])[1]/dim(default.train[,3:4])[1]
}

dmvnorm<-function(x,mu,sigma){
    p<-length(mu)
    mu<-c(mu)
    x<-c(x)
    f=1/(2*pi)^(p/2)/(det(sigma))^(1/2)*exp(-0.5*t(x-mu)%*%solve(sigma)%*%(x-mu))
    return(f)
}

PP<-function(x,pro,mu,sigma){
    K<-length(pro)
    PP<-numeric(K)
    for (i in 1:K){
        PP[i]<-pro[[i]]*dmvnorm(x,mu[[i]],sigma[[i]])
    }
    PP<-PP/sum(PP)
    return(PP)
}

Y.pred<-numeric(dim(default.test)[1])
Pprob<-matrix(0,ncol=2,nrow=length(Y.pred))
for (i in 1:dim(default.test)[1]){
    Pprob[i,]<-PP(unlist(default.test[i,3:4]),pro,mu,S)
    Y.pred[i]<-which.max(Pprob[i,])
    }

Y.hat<-character(length(Y.pred))
Y.hat[Y.pred==1]<-"No"
Y.hat[Y.pred==2]<-"Yes"

table(pred=Y.hat,true=default.test[,1])
##      true
## pred    No  Yes
##   No  4814  130
##   Yes   12   44
sum(default.test[,1]!=Y.hat)
## [1] 142
sum(default.test[,1]!=Y.hat)/length(Y.hat)
## [1] 0.0284

Bayes classifier는 predictor로 이산형, 연속형 변수를 섞어서 예측할 수가 없다. 문제에서도 나와있듯이 연속형 변수인 balance, income만을 predictor로 사용하였다.

Bayes classifier에서 qda를 구하는 코드로 작성하고, 이를 바탕으로 Validation set approach로 error rate를 구하였다. error rate는 0.0284로 나쁘지 않은 분류 성능을 보여주었다.

겉으로 보기에는 적절해보이지만, 은행 입장에서는 채무불이행인데 아닌 것으로 밝힌 사람이 많으면 많은 손해이다. 따라서 이 분류 뿐만아니라 cost function을 함께 활용하면 은행 입장에서 얼마나 손해/이익인지도 파악할 수 있을 것이다.

#LOOCV
default1 <- Default[,c(1,3,4)]
fitloocv<-lda(default~.,data=default1,cv=T)
predloocv<-predict(fitloocv,default1)$class
table(predloocv,default1[,1])
##          
## predloocv   No  Yes
##       No  9647  256
##       Yes   20   77
mean(predloocv!=default1[,1])
## [1] 0.0276
#10-fold CV
K<-10
ind<-(1:n)%%K+1
set.seed(20144607)
folds<-sample(ind,n)
kfoldcv<-character(n)
for (k in 1:K){
    fit<-lda(default~.,data=default1,subset=which(ind!=k))
    kfoldcv[ind==k]<-as.character(predict(fit,default1[ind==k,])$class)
}
table(kfoldcv,default1[,1])
##        
## kfoldcv   No  Yes
##     No  9647  255
##     Yes   20   78
mean(kfoldcv!=default1[,1])
## [1] 0.0275

LOOCV, 10-fold CV로도 error rate를 구하였는데, 이 때에는 lda를 활용하였다. 에러 비율이 0.03 미만으로 우수한 분류 performance를 보여주었다. qda도 활용하였으나 lda와 error rate가 그렇게 큰 차이가 나지 않았다.(0.0001미만) 따라서, covariance matrix가 다르며 많은 변수가 필요하여 LOOCV, 10-fold CV에서는 복잡한 모델이 되는 qda를 쓰지 않기로 했다. Law of parsimony에 따라 lda만을 사용하였다. 정리하면, Bayes classifier의 error rate는 0.0284, 0.0276, 0.0275로 우수하다.

문제

2. Construct a naive Bayes’s classifier to predict “default” using “student”, “balance”, and “income” variables. Estimate the test error rate using (1) VS approach, (2) LOOCV, and (3) 10-fold CV

#VS approach
library(ISLR)
library(e1071)
fit<-naiveBayes(default~.,data=default.train)
pred.default<-predict(fit,default.test)
table(pred=pred.default,true=default.test[,1])
##      true
## pred    No  Yes
##   No  4802  124
##   Yes   24   50
mean(pred.default!=default.test[,1])
## [1] 0.0296
#LOOCV
n <- dim(Default)[1]
error.loocv <- vector(mode = "logical", n)
for( i in 1:n){
  fit.loocv <- naiveBayes(default ~ ., data=Default[-i,])
  pred2 <- predict(fit.loocv, newdata=Default[i,])
  error.loocv[i] <- (pred2 != Default[i,]$default)
}
mean(error.loocv)
## [1] 0.0295
#10-fold CV
K<-10
ind<-(1:n)%%K+1
set.seed(20144607)
folds<-sample(ind,n)
predcv<-character(n)
for (k in 1:K){
    fit<-naiveBayes(default~.,data=Default,subset=which(ind!=k))
    predcv[ind==k]<-as.character(predict(fit,Default[ind==k,]))
}
table(predcv,Default[,1])
##       
## predcv   No  Yes
##    No  9615  244
##    Yes   52   89
mean(predcv!=Default[,1])
## [1] 0.0296

이번에는 이산형과 연속형 변수가 섞인 상태에서도 활용이 가능한 naive bayes를 적용하였다. discrete 변수인 student와 continuous predictor인 balance, income을 섞어서 분류 예측을 진행하였다. 세가지 error rate는 각각 0.0296, 0.0295, 0.0296으로 모두 비슷한 error rate를 보여주었다.

(1)과 (2)에서 각각 classifier의 error rate를 비교해보면, 아주 약간이나마 Bayes classifier가 높은 분류 예측 성능을 보여준다. 아무래도 naiveBayes에서 이산형 변수(student)가 섞이면서 약하게나마 과대적합이 발생했을 것이라고 추측하고 있다. 물론 naiveBayes 모델은 이산형과 연속형 변수 모두를 예측변수(predictor)로 사용할 수 있다는 점이 우수하므로 이산형 변수가 예측 변수로 사용해야하는 경우에는 유용할 것이다.