R 고급 caret을 이용한 머신러닝(로지스틱 회귀 colon 데이터 셋 )

  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 패키지의 동일한 이름의 좋은 함수 가 있다.  이 함수에는 높은 상관관계를 가진 예측 변수의 군집을 찾는 식으로 변수 순서를 재배치 할 수 있는 여러 옵션이 있다. 

# 상관관계 구조를 시각적으로 확인한다.  
  corrplot(correlations, order ="hclust")
상관관계 구조 시각화
상관관계를 토대로 변수를 걸러낼 대 findCorrelation 함수를 사용하면 다중 공선성의 문제 즉 변수간의 상관관계가 높아 사용하지 못하는 변수들을 걸러낼 수 있다. 

# 상관관계가 높은 것은 데이터를 걸러낸다. 
  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개 였고,  크로스 벨리데이션도 실행 하였다. 





댓글 없음:

댓글 쓰기

[주식 클로드 자동매매 프로젝트] 제2편. 데이터 인프라 구축 — 모델보다 데이터가 먼저다

 머신러닝 모델을 이야기하기 전에, 그 모델이 먹는 데이터가 어디서 어떻게 왔는지부터 정직하게 밝혀야 한다. 이 프로젝트에서 가장 많은 시간이 들어간 부분은 화려한 모델 튜닝이 아니라, "내가 정말 그 데이터를 갖고 있는가"를 확인하...