이 글 시리즈는 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)
'데이터 사이언스 > 머신러닝 및 모델링' 카테고리의 다른 글
의사결정나무/Decision Tree 총정리, 1편 회귀 문제에서 트리는 어떻게 돌아가는가? (0) | 2021.04.17 |
---|---|
(데이터과학 인터뷰 질문) (4) 샘플링과 리샘플링, 3편 : 교차검증 (1) (0) | 2020.11.06 |