본문 바로가기

데이터 사이언스/머신러닝 및 모델링

(데이터과학 인터뷰 질문) (5) 샘플링과 리샘플링, 4편 : 교차검증과 하이퍼 파라미터 튜닝

이 글 시리즈는 zzsza.github.io/data/2018/02/17/datascience-interivew-questions/에 있는
<데이터사이언스 인터뷰 질문 모음집>에 스스로 대답해보면서 정리해보고자 적어가는 글입니다.

주인장 분께 감사의 말씀 드립니다!

 

 

 


리샘플링의 다양한 방법론들, 4편
교차검증(Cross-validation)과 하이퍼 파라미터 튜닝


 

  • 이번 글에서는 교차검증을 실제 모델링에서 사용하는 다른 방법인 하이퍼파라미터 튜닝에 대해서 알아보자.
  • 이 아이디어는 단순하면서도 꽤나 강력하다.
  • 기본 개념은 리샘플링 시리즈에서 계속 다루는 내용과 동일하다.
  • 즉, 주어진 데이터셋을 얼마나 최대한 뽑아먹으면서, variance는 줄이고, 다른 데이터셋에서도 잘 작동할 만한 모델을 수립하고자 하는 것이다.

 

  • 우리가 실제로 다루게 되는 많은 모델들이 하이퍼파라미터(hyperparameter, 굳이 번역하자면 초모수, 이하 HP)라는 것을 가지고 있다.
  • learning parameter라고 부르는 책/논문도 있다고 하는 듯 하다.
  • HP의 가장 대표적인 예가 KNN(K-Nearest Neighbors) 모델의 K 개수다. 몇 개의 이웃을 생성할지를 결정한다.
  • 이 외에도 수많은 모델의 수많은 HP가 존재한다.

  • 물론 데이터를 보면서 대략 K값을 정할 수도 있다.
  • 하지만 데이터가 3차원을 넘어서면(대부분의 실전 데이터가 그렇겠지만) 시각적으로 파악하는 것이 굉장히 난감해질 수 있다.
  • 게다가 어떤 모델은 HP가 하나가 아니라 여러개다.
  • 예를 들어서 다음은 R의 그 유명한 xgboost 모델의 공식 문서를 캡쳐한 것이다.

  • 물론 '보통 사람들이 이 HP는 이 값을 사용하더라'라는 카더라 같은 정보들이 돌아다니기는 한다.
  • 근데 그 값들이 내 데이터에 적합할거란 보장이 어디 있는가?
  • 그렇다면 적절한 값은 도대체 어떻게 정하는가? 예를 들어서 labmda L2 정칙화 term과, colsample_bytree라는 HP를 최적화해보고 싶다고 하자.
  • L2는 0~5 사이의 정수, colsample은 0.5~1 사이의 0.1간격 실수라고만 해도, 5*5=25가지의 경우의 수가 생긴다.
  • 데이터가 크면 클수록 이 과정은 상당히 오랜 시간이 걸릴 것이다.
  • 이럴때 Random search 혹은 Grid search등의 테크닉을 사용한다(이건 사실 다른 주제이긴 하다. 다른 글에서 아마 다룰 예정. 그러나 필요에 의해서 짚고 넘어간다.)

  • 어쨌든, 이렇게 다양한 HP 값들이 존재할 때, 우리는 어떤 HP값이 '적합'한 값인지 알아 최적화할 수 있을까?
  • 가장 쉽고 직관적인 방법은 training set에서 정해진 HP값을 이용해 모델링, test set에서의 model performance(예:MSE)를 확인해보는 것이다.
  • 그러나, 리샘플링 편에서 반복적으로 이야기하듯이, 딱 한번의 테스트 결과가 적절한 fitness 값을 제공할 거라고 기대하기는 힘들다.
  • 그래서, 쉽게 말해서 model performance의 하나의 값을 보자는 게 아니라, model performance의 분포를 보자는 것이다

 

  • 다음은 간단하게 작성해 본 K-Means Clustering의 HP, 즉 K 개수를 5-fold CV를 이용해 작성하는 방법이다.

 

 


    #1. 필요한 패키지 로드

    library(factoextra)
    library(fpc)
    library(NbClust)

 

    #2. 임의의 모집단 데이터 생성

    #이항분포 + 노멀분포, 모집단으로 가정

    x <- rbinom(500, 1, 0.3)+rnorm(500, 0, 0.2)

    y <- rbinom(500, 1, 0.5)+rnorm(500, 0, 0.2)
    df <- data.frame(x,y)

    plot(df)

 

    #3. 랜덤 샘플링
    df_sample <- df[caret::createDataPartition(df$y, p=0.5, list=T)$Resample1, ]

 

    #4. 5-Fold index 생성
    df_fold <- caret::createFolds(df_sample$y, k = 5, list = T)

    #5. 각 Fold 별로 3~6 사이의 K값 테스트

    samp_result <- vector('list', 5)
    for (i in 3:6){
    
      for (j in 1:5){
      samp_result[[j]][[i]] <- eclust(df_sample[df_fold[[j]],], FUNcluster = 'kmeans', 
                                      hc_metric = 'euclidean', k = i)
      }
      
    }

 

    #6. 실루엣 인덱스(클러스터링 성능 평가 지표)
    result_df <- matrix(nrow=4, ncol=5)
    
    for (i in 1:5){
      for (j in 3:6){
        result_df[j-2,i] <- samp_result[[i]][[j]]$silinfo$avg.width

        
      }
    }    

    result_df <- as.data.frame(result_df)

    colnames(result_df) <- paste('Fold', 1:5) ; rownames(result_df) <- paste('K = ', 3:6)

 


결과적으로 다음과 각 k값에 대한 실루엣 인덱스(performance metric)의 평균/분산 분포 값을 얻었다.

  K = 3 K = 4 K =5 K =6
Mean 0.542 0.571 0.526 0.503
Variance 0.009 0.006 0.0001 0.0009

 

 

  • 이러한 경우, 평균 실루엣 인덱스는 K=4인 경우가 가장 높았으나 분산은 K=5인 경우가 가장 낮았다.
  • 실제 모집단에서는 K=4가 적정한 클러스터로 보였으니, 다음 스텝으로 k-fold의 k값(몇 번 데이터를 나눌 것인지)을 높여 K=4와 K=5를 비교해보는 편이 좋을 듯 하다.

 

 

 

출처

<Elements of Statistical Learning>, Hastie et al.

Cross Validaiton, Wikepedia
en.wikipedia.org/wiki/Cross-validation_(statistics)