[ADP] R로 하는 Ensemble(앙상블)모형 - Bagging, Boosting, RandomForest

2020. 8. 2. 13:53ADP | ADsP with R/Knowledge

 Ensemble 모형에는 대표적으로 Bagging/RandomForest/Boosting이 있다. 이 앙상블 기법에 대한 개념적 설명은 아래 링크를 통해 남겨 놓겠다. 이번 게시글에는 R을 활용해 Bagging/RandomForest/Boosting을 실습하려고 한다. 

 

Bagging/RandomForest

https://todayisbetterthanyesterday.tistory.com/48

 

[Data Analysis 개념] Ensemble(앙상블)-2 : Bagging, RandomForest

 앙상블에 대한 종류와 전반적인 설명은 아래 링크에 존재한다. 이 게시글에서는 앙상블 모형중 Bagging과 RandomForest에 대해서 알아보겠다. https://todayisbetterthanyesterday.tistory.com/47 [Data Analysi..

todayisbetterthanyesterday.tistory.com

Boosting

https://todayisbetterthanyesterday.tistory.com/49

 

[Data Analysis 개념] Ensemble(앙상블)-3 : Boosting(Adaboost, Gradient Boosting)

1. Boosting  boosting은 오분류된 데이터에 집중해 더 많은 가중치를 주는 ensemble 기법이다. 맨 처음 learner에서는 모든 데이터가 동일한 가중치를 갖는다. 하지만, 각 라운드가 종료될 때마다, 가중치

todayisbetterthanyesterday.tistory.com

 

 

1. Bagging

# 패키지 설치
install.packages("adabag")

# 라이브러리 & 데이터 로딩
library(adabag)
data(iris)

# Bagging model
iris.bagging <- bagging(Species~., data=iris, mfinal=10)
iris.bagging$importance

 위에서 mfinal을 통해 10번 반복복원추출하여 학습한다고 명령하였다. 이를 통해 나온 변수의 중요도를 보면 위의 그림과 같다. 분류기의 분류기준을 보는 것은 아래 plot을 통해 직관적으로 볼 수 있다. 

# 도식화
plot(iris.bagging$trees[[10]])
text(iris.bagging$trees[[10]])

 위의 결과는 bagging 분류결과를 tree형태로 표현한 것이다. 변수 중요도 부분에서 봤던 Petal.Length와 Petal.Width가 분류기의 기준으로 작용한 것을 확인할 수 있다. 이제 이 모형의 정확성을 확인해보자.

# 예측값
pred <- predict(iris.bagging, newdata=iris)

# 정오분류표
table(pred$class, iris[,5])

 예측 결과를 pred라는 변수에 넣었다. 그리고 이를 confusion_matrix,정오분류표로 표현하였다. 위의 결과를 보면 setosa의 경우는 50개 중에서 50개, versicolor는 54개 중에서 49개, virginica는 46개 중에서 45개를 정확하게 분류한 것을 볼 수 있다. 즉, 성능이 좋은 편이다. 물론 학습데이터가 그대로 예측에 사용되었기 때문일 수도 있다. 

 

 

2. Boosting

# 라이브러리 & 데이터 로딩
library(adabag)
data(iris)

# boosting model
boo.adabag <- boosting(Species~., data=iris, boos=TRUE, mfinal=10)
boo.adabag$importance

 위의 경우는 가장 기본적인 boosting기법 AdaBoost기법이다. 동일하게 bagging처럼 반복 복원추출과정을 거치면서, 각 step에서 잘못 분류된 데이터에 가중치를 부여하여 표본을 추출한다. 그 결과로 보았을 때, Sepal 변수의 중요도가 상승한 것을 알 수 있다. 

# 도식화
plot(boo.adabag$trees[[10]])
text(boo.adabag$trees[[10]])

 AdaBoosting의 Tree는 보다 더 leaf-wise하고, depth 또한 더 깊은 것을 확인할 수 있다. 

 

# 예측값
pred <- predict(boo.adabag, newdata = iris)

# 정오분류표
tb <- table(pred$class,iris[,5])
tb

 

 위의 경우는 bagging보다 더 좋은 성능을 보였다. 물론 train 데이터를 예측한 것이기에 Overfitting이 되었다고 볼 수도 있다. 

# 오분류율
error.rpart <- 1-(sum(diag(tb)/sum(tb)))
error.rpart

 위의 정오분류표에서 모두 잘 분류된것을 확인할 수 있었다. 그렇기에 오분류율 또한 0이다. 

 

 setosa의 경우는 항상 분류가 잘 되는 것을 보았다. 그렇기에 setosa를 제외하고 다시 boosting을 한 번 진행해보자. 아래의 실습에서는 ada 패키지의 ada()함수를 통해서 adaboosting을 진행할 것이다. 

# Adaboost library
install.packages("ada")
library(ada)

# setosa 제외
data(iris)
iris[iris$Species != "setosa", ] -> iris
n <- dim(iris)[1]
# 60개의 train data / 40개의 test data
raind <- sample(1:n, floor(.6*n), FALSE)
testd <- setdiff(1:n, traind)
iris[,5] <- as.factor((levels(iris[,5])[2:3])[as.numeric(iris[,5])-1])
# Ada boost 훈련용 데아터로 모형구축 
# test데이터에 대한 오분류율 0%
gdis <- ada(Species~., data=iris[traind,],iter=20, nu=1,type="discrete")
gdis <- addtest(gdis, iris[testd, -5], iris[testd, 5])
gdis

 위의 결과를 plot, varplot, pais함수를 통해서 시각화 해보자.

# plot()
plot(gdis,TRUE,TRUE)

 plot()함수는 오차와 일치도를 나타내는 kappa계수를 그려준다. 두 개의 TRUE input은 train/test 모두 그림을 그린다는 것이다. 

# varplot()
varplot(gdis)

 varplot함수는 변수의 중요도(importance)를 나타낸다. setosa를 제외한 versicolor와 virginica를 구분하는데 Sepal.Width 변수가 분류에서 가장 중요하다는 것을 뜻한다. 이는 분명하게 위에서 setosa가 있었을 때의 결과와는 다르다.

# pairs()
pairs(gdis, iris[traind,-5], maxvar=4)

 pairs()함수는 두 예측변수의 조합별 분류결과를 그려준다. maxvar= 옵션은 변수의 수를 지정하는 것인데, 이때, 중요도가 높은 순으로 상위 변수의 개수를 선택할 수 있다. 위에 code에서는 변수의 수가 중요한 것으로 상위 4개를 그린것이다(즉, 전부 다 표시했다.)

3. RandomForest

# 라이브러리 로딩
install.packages("randomForest")
library(randomForest)
library(rpart)

# 데이터 로딩
data(stagec)

# train/test split
stagec1 <- stagec[complete.cases(stagec),]
set.seed(1234)
ind <- sample(2, nrow(stagec1), replace = TRUE, prob = c(0.7,0.3))
trainData <- stagec1[ind==1,]     # n = 102
testData <- stagec1[ind==2,]      # n = 32

# randomforest
rf <- randomForest(ploidy~., data=trainData, ntree=100, proximity=TRUE)

# confusion_matrix
table(predict(rf),trainData$ploidy)

# model summary
print(rf)

 위의 결과창을 보면 OOB estimate of error rate이 존재한다. 앙상블에서는 검증용 데이터를 사용하지 않고 bootstrap(반복복원추출)에서 제외된 데이터들을 대상으로 1차적인 오류율을 구할 수 있다. 이를 Out of Bag(OOB) error라고 한다.  

# plot
plot(rf)

 위의 plot함수는 트리의 수에 따른 종속변수의 범주별 오분류율을 나타낸다. 검은색은 전체 오분류율. 오분류율이 1로 나타난 파란 점선은 aneuploid 범주로 개체수가 매우 작은 범주에서 발생된 오분류율이다. 

# 중요도
importance(rf)

# 중요도 plot
varImpPlot(rf)

 

 위의 출력창과 plot을 통해 각 변수의 중요도를 확인할 수 있다. 위 그림은 해당 변수로 분할작업이 이루어질때, 불순도(impurity)의 감소가 얼마나 일어나는지 나타낸다. 즉 Gini지수가 노드의 불순도를 나타내는 값이다. 그리고 불순도의 감소가 클수록 순수도가 증가한다. 위의 경우는 분류이기에 Gini지수를 통해서 표현되지만, 회귀의 경우 잔차제곱합을 통해서 측정된다. 

# test 데이터 예측
rf.pred <- predict(rf, newdata = testData)
table(rf.pred, testData$ploidy)

# margin값
plot(margin(rf))

 위의 예측 정오분류표와 margin표를 통해서 정확도를 확인할 수 있다. margin이란 랜덤포레스트의 classifier가운데 정분류를 수행한 비율을 다른 클래스로 분류한 비율의 최대치를 뺀 값을 나타낸다. 즉, positive margin은 정확한 분류이며, negative margin은 그와 반대이다. 

 

# party 패키지를 활용한 randomforest
install.packages("party")
library(party)
set.seed(1234)
cf <- cforest(ploidy~., data=trainData)
cf.pred<-predict(cf,newdata=testData, OOB = TRUE, type="response")

 위의 코드는 party패키지의 cforest함수를 사용하여서 randomforest를 진행할 수 있기에 잠깐 보여주는 예시이다.