caret은 대표적인 머신러닝 패키지이다. 이것이 있어서, R에서는 파이썬 보다 좋은 경쟁력을 가지고 분석 할 수 있다. 즉 파이썬에서 경쟁력이 있는 것은 비정형 자료 즉, 이미지, 문자, 음성등 과 같은 것이다. 개인 적으로는 파이썬의 사이킷런 보다, 이것이 더욱 좋다.
아래의 예제 코드는 아래의 책을 참고 하여 작성 하였다.
로지스틱 회귀 실전 예측분석 모델링 |
1. 변수의 선택
변수가 많을 때 변수간 상관관계를 가지고 필터링 하는 예제이다. 변수가 많을 때 주성분 분석하여 변수의 비중을 알아 낼 수 있었지만, 이건은 변수간의 상관관계를 가지고 정리 한것이다.
# 서바이벌 패키지를 읽어 온다.
library(survival)
library(corrplot)
library(caret)
library(dplyr)
library(tidyr)
library(e1071)
결측치를 찾아 본다 결측치가 있으면, 분석 할 수 없으므로, 이번에는 결측치 있는 셀은 삭제 하기로 한다.
# na 찾아 보기
sum(is.na(colon))
## [1] 82
# 머신러닝을 돌리기 위해 결측치 제거
colon <- na.omit(colon)
머신러닝 할때는 범주형 데이터인 rx : 치료방법 (“Obs”=ervation, “Lev”=amisole, “Lev+5FU”=amisole + 5-FU) 은 인식 할 수 없으므로, 원-핫 인코딩 하여, 각 방법별로, 숫자 1,0을 만든다.
# 범주형 자료로 되어 rx를 원핫인코딩 한다.
dummy <- dummyVars("~.", data= colon)
new_colon <- data.frame(predict(dummy, newdata = colon))
데이터 레벨의 차이가 크면, 머신러닝에서 연산 할 수 없어서 레벨을 맞추어 준다. 이것은 이후에 나오는 BoxPlot 분석 할때, 매우 용이하다.
# 데이터를 스케일링 한다. (age, nodes, extent, time, etype)
new_colon <- new_colon %>%
mutate ( age = scale(age),
nodes = scale(nodes),
extent = scale(extent),
time = scale(time))
분산이 0에 가까운 예측 변수를 걸러내고자 할 때는 caret 패키지의 nearZeroVar를 사용해야 하며 예측 변수간의 상관관계를 가지고 변수를 걸러내고 싶다면 cor 함수를 사용해 예측 변수간의 상관관계를 계산 하여야 한다.
# 종속변수를 아래와 같이 빼고, 예측변수의 상관관계 시각화
cor_colon <- new_colon %>% select(-c(status))
# 분산이 0인것 삭제
except <- c(nearZeroVar(cor_colon))
cor_colon <- cor_colon[-c(except,1)]
# 상관관계 분석
correlations <- cor(cor_colon)
# 상관관계 구조를 시각적으로 확인한다.
corrplot(correlations, order ="hclust")
상관관계 구조 시각화 |
# 상관관계가 높은 것은 데이터를 걸러낸다.
highCorr <- findCorrelation(correlations, cutoff = .75)
cor_colon <- cor_colon[, -highCorr]
# 아래에 상관계수가 높은 데이터 셋을 걸러내어 데이터가 나왔다.
glimpse(cor_colon)
## Rows: 1,776 ## Columns: 13 ##
$ rx.Obs <dbl> 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,… ## $ rx.Lev <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,… ## $ rx.Lev.5FU <dbl> 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1,…
## $ sex <dbl> 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0,… ## $ age <dbl[,1]> <matrix[26 x 1]> ## $ obstruct <dbl> 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0… ## $ adhere <dbl> 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,… ## $ differ <dbl> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,… ## $ extent <dbl[,1]> <matrix[26 x 1]> ## $ surg <dbl> 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1,… ## $ node4 <dbl> 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0… ## $ time <dbl[,1]> <matrix[26 x 1]> ## $ etype <dbl> 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
참고로 형광색 부분은 원-핫 인코딩 된것이다.
아래는 데이터 전처리 하기전에 Boxplot으로 어떻게 할 것인가 결정 하는 화면이다.
# 데이터 확인을 위한 BOXPLOT 그리기
cor_colon %>%
gather( key = "변수명", value = "값") %>%
group_by(변수명) %>%
ggplot(aes(변수명, 값, fill= 변수명)) +
geom_boxplot() +
theme( axis.text.x = element_text(angle = 90),
legend.position = "none")
adhere. age, differ, etype extent, obstruct 에서 이상치(outlier)가 많이 나왔다. 이것은 모델을 돌리면서 전처리 할 것이다. 특히 age나 adhere 같은 변수는 정규분포에 근사하지 못하므로 center를 맞출 것이다.
2. 데이터 분할, 모델 튜닝/평가
데이터 분할을 왜 하는지 처음에 이것을 보았을때 무슨 의미인지 알 수 가 없었다. 하지만 모집단 전체의 데이터를 사용하여, 적합한 모델링을 할 수 있는 경우도 있지만, 대부분 최적의 샘플링을 하여 예측 하게 된다. 특히 단일 테스트 세트로 모델을 평가하기 위한 대안으로 훈련 데이터 세트는 여러가지로 수정 하여 사용한다.
모집단 전체를 선택하지 왜 훈련셋을 만드느냐? 쉽게 설명 하면 아래와 같다, 전국에 대통령 선거 여론 조사를 하였는데, 어떤 지역과 특정 연령층의 응답이 높을 경우 모든 데이터를 샘플을 전부 사용하는 것 보다는 지역과 연령층을 고르게 재 샘플링 하는 것이 오히려 예측의 정확도가 높아 진다. 이 문서에서는 모델 성능 평가까지만 다룰 것이다.
모델 구축의 일반적인 단계는 아래와 같다.
- 예측 데이터 전처리
- 모델 변수 추정
- 모델에 사용할 예측 변수 선정
- 모델성능평가
- 예측규칙 미세조정(ROC 곡선등)
데이터 분할
모델 실행 데이터
colondf <- cbind(cor_colon, colon$status)
colnames(colondf)[14] <- "status"
colondf$status <- as.factor(colondf$status)
# 클래스 레벨을 정한다.
levels(colondf$status) <- c("relapse", "dead")
# 데이터 셋 나누기 8:2
set.seed(1001)
inx <- createDataPartition(colon$status, p = 0.8, list = F)
train <- colondf[ inx, ]
test <- colondf[-inx, ]
선택된 데이터를 분할 하고, target 변수은 status는 머신러닝에서 1,0을 인식 하지 못하므로, 문자형태로 클래스 레벨을 정한다.
그리고, 데이터셋은 8:2로 나눈다. 7:3으로 할 수 있으나 대부분 8:2로 많이 나눈다. 파이썬 사이킨런과, 딥러닝은 데이터셋 나누는 것이 조금 다르다.
80%의 데이터는 층화 샘플링 하는 것이 좋다. 예전 학부에서 통계학을 배울때, 데이터 샘플링이 가장 중요하다고 하였는데, 편향되지 않게 샘플링 하는 것이 좋다고 하였다. 편향되지 않게 샘플링 하는 것은 리샘플링이 가장 좋다.
# cross validation 교차 검증 시행
control <- trainControl(
method = "repeatedcv",
number = 10,
repeats = 5,
search = "grid",
classProbs = TRUE)
앞서서 BoxPolt으로 검토 한 바와 같이 BoxCox, center, corr 정의한다.
# preprocess 데이터 전처리
preProc <- c("BoxCox",
"center",
"corr"
)
그리고 이 둘을 묶어서 데이터 모델을 돌린다.
# logistic regression
system.time(
logis <- train( x = train[, -14],
y = train[, "status"],
method = "glm",
metric = "Accuracy",
trControl = control,
preProcess = preProc)
)
## user system elapsed
## 8.794 0.040 8.855
logis
## Generalized Linear Model
##
## 1421 samples
## 13 predictor
## 2 classes: 'relapse', 'dead'
##
## Pre-processing: Box-Cox transformation (1), centered (10), ignore (3)
## Resampling: Cross-Validated (10 fold, repeated 5 times)
## Summary of sample sizes: 1279, 1279, 1279, 1279, 1279, 1279, ...
## Resampling results:
##
## Accuracy Kappa
## 0.9307545 0.861386
정확도는 93% 정도 나왔고 Box-Cox transformations은 1개 실행 하였고, 중심화적도를 맞추는 것은 10개, 분산이 같이 무시한것은 3개 였고, 크로스 벨리데이션도 실행 하였다.
댓글 없음:
댓글 쓰기