데이터분석가 | 취준생

[모델 훈련 및 예측] model_selection / Cross Validation 본문

Data Analysis

[모델 훈련 및 예측] model_selection / Cross Validation

su_hyeon 2023. 1. 5. 16:04

사이킷런 패키지 안에 다양한 모듈이 존재한다고 했다.

이번에는 그 중에서도  model_selection에 대해서 소개하고자 한다.

 

model_selection 모듈

model_selection 모듈은 학습 데이터 셋과 테스트 데이터 셋으로 분리,  교차검증 분할 및 평가, 하이퍼 파라미터 튜닝을 하기 위한 다양한 함수와 클래스를 제공한다.

 

train_test_split()

데이터 셋을 나누어야 할 이유를 설명하기 위해서 먼저, 학습 데이터 셋과 테스트 데이터 셋으로 나누지 않고 모델을 돌려보았다.

데이터를 나누지 않고 수행

예측 정확도를 보면, 100%가 나온 것을 볼 수 있다.

이는 당연한 결과인데, 모델을 학습할 때, fit() 메서드에서 학습한 데이터를 predict에서 사용했기 때문에 정답이 주어진 것을 모델에 돌리니 다 올바르게 맞추는 것이다.

 

데이터 셋을 나누지 않고 사용하면 의미없는 결과가 나오기 때문에 반드시 학습 데이터와 테스트 데이터로 나누어주어야 한다.

 

다음으로 train_test_split 함수를 이용하여 데이터를 나눈 뒤에 모델을 실행시켰다.

train_test_split 파라미터에는 feature 데이터 세트, label 데이터 세트를 반드시 넣어주어야 하고 밑에는 선택적으로 넣어주면 된다.

 

-> test_size : 전체 데이터에서 테스트 데이터의 비율을 얼마로 할 것인지 정하는 파라미터이다.

-> train_size : 전체 데이터에서 훈련 데이터의 비율을 얼마로 할 것인지 정하는 파라미터이다. 주로 test_size를 더 많이 활용한다.

-> shuffle : 데이터를 분리하기 전에 데이터를 미리 섞을지 결정하는 파라미터이다. defalut 값은 True이기 때문에 선택적으로 결정해주면 된다. 

-> random_state : 호출할 때마다 동일한 학습/테스트 데이터 세트를 생성하기 위해 주어지는 난수 발생값으로 아무 숫자나 지정해주면 된다.

 

 

데이터를 나누고 수행

 

교차검증(Cross Validation)

교차검증이란, Cross Validation(CV라고도 함)으로 train_test_split을 이용했을 때 발생하는 문제점인 과적합(Overfitting)을 해결할 수 있는 방법이다.

 

과적합이란, 모델이 학습 데이터에만 과도하게 최적화 되어서 다른 데이터를 사용했을 때 모델이 예측을 잘 수행하지 못하는 것을 의미한다. 이렇게 되면 모델의 성능이 떨어지게 된다.

 

교차검증을 조금 더 쉽게 이야기하면 위의 학습 데이터와 테스트 데이터로 나누어 수행한 경우와 비교해서 말할 수 있다.

train_test_split은 모델의 학습을 한번만 하는 경우이고, 교차검증은 k를 지정해주어 모든 데이터 셋을  k번 만큼 학습을 해주기 때문에 모델의 성능이 더 좋아질 수 있다.

 

그러기 위해서 교차검증을 실행할 때 기존의 학습 데이터와 테스트 데이터로 나눈 것에서 학습 데이터를 한번 더 쪼개어

학습 데이터, 검증데이터, 테스트 데이터 총 3가지로 나누어 준다.

그래서 검증 데이터로 1차적으로 예측해본 뒤에 최종적으로 테스트 데이터로 예측해준다.

 

교차검증에는 대표적으로 K 폴드(K-fold) 교차검증과 Stratified K 폴드로 나눌 수 있다.

 

K-fold 교차검증 

: 가장 보편적으로 사용되는 교차검증으로, k개의 데이터 폴드 세트를 만들어서 k번만큼 각 폴드 세트에 학습과 검증 평가를 반복적으로 수행하는 방법이다. 

 

출처 : https://nonmeyet.tistory.com/entry/KFold-Cross-Validation%EA%B5%90%EC%B0%A8%EA%B2%80%EC%A6%9D-%EC%A0%95%EC%9D%98-%EB%B0%8F-%EC%84%A4%EB%AA%85

 

위의 그림과 같이 k개를 지정해주는데, 가장 많이 사용하는 defalut = 5이다.

 

먼저 데이터를 k개로 나눈 뒤에 각각의 데이터에서 학습 데이터(4)와 검증데이터(1)를 같은 비율로 나누어준다.

이렇게 예측시켜준 모델을 검증한 뒤에 그것들의 평균을 구해서 최종평가를 해준다.

 

Stratified K 폴드

 Stratified K 폴드는 데이터의 라벨(label)값이 불균형할 때에 주로 사용하는 교차검증이다.

만약 라벨 값이 불균형하면, 데이터를 나누고 검증을 할 때 데이터의 분포가 불균형하게 들어가기 때문에 비율이 맞지 않을 수 있다. 

일반적으로 분류(Classification)는 Stratified K 폴드를 사용해야 한다. 

또, 회귀(Regression)에서는 Stratified K 폴드가 지원되지 않는다. 왜냐하면, 회귀는 라벨 값이 수치형 변수로 되어 있기 때문에 결정값별로 분포를 정하는 의미가 없기 때문이다.

 

-> cross_val_score()

K 폴드와 Stratified K 폴드를 실행시킬 수 있는 코드들이 존재한다. 하지만, 사이킷런은 교차검증을 더 편리하게 수행할 수 있는 코드를 지원한다.

 

cross_val_score(estimator, X, y, scoring, cv) 안에 있는 파라미터가 주요 파라미터이다.

 

-> estimator : 사이킷런의 알고리즘 클래스를 지정해준다 (쉽게 말하면 모델 지정)

-> X : 피처 데이터 세트

-> y : 레이블 데이터 세트

-> scoring : 예측 성능 평가 지표

-> cv : 교차 검증 폴드 수

 

cross_val_score()

cross_val_score() 같은 경우는 k 폴드인지 stratified 폴드인지 지정해주지 않는다.

왜냐하면 만약 estimator가 분류에 해당하면 자동적으로 stratified k 폴드로 지정해주고, 그게 아닌 경우에는 모두 k 폴드로 지정해주기 때문이다. 

 

GridSearchCV

먼저 , 하이퍼파라미터에 대한 설명을 진행하도록 하겠다. 

하이퍼 파라미터란, 예측을 진행하기 위해 필요한 알고리즘 파라미터들이 있는데, 그 중에서도 가장 최적의 예측을 진행시키는 파라미터들을 하이퍼 파라미터라고 한다.

 

GridSearchCV는 Classifier나 Regressor와 같은 알고리즘에 사용되는 하이퍼 파라미터를 순차적으로 입력하면서 자동적으로 최적의 파라미터를 도출할 수 있는 방안을 제공한다.

 

-> GridSearchCV 파라미터

estimator : 분류나 회귀의 알고리즘

param_grid : 파라미터들의 집합이 딕셔너리 형태로 되어있는 변수를 입력한다.

scoring : 예측 성능을 측정할 평가 방법 지정

cv : 교차검증을 할 때 분할되는 학습/테스트 세트의 갯수 지정

refit : 디폴트 값은 True이고, 이는 하이퍼 파라미터를 찾은 뒤 입력된 estimator 객체에 재학습 시킨다는 의미

 

파라미터 지정하는 법

- 위의 그림은 의사결정나무 모델의 하이퍼 파라미터를 순차적을 지정해준 변수를 생성한 것이다.

GridSearchCV

- parameters 라는 변수에 모델 알고리즘의 하이퍼 파라미터를 지정하고 GridSearchCV의 param_grid에 입력

데이터 프레임으로 변환 후 최적의 하이퍼 파라미터 확인

- scores_df 변수에 그리드 서치를 한 것을 데이터 프레임으로 변환

- scored_df[[]] 코드를 이용하여 필요한 열들을 추출한 표를 확인할 수 있다.

 

- grid_dtree.best_params_ : 최적의 파라미터 추출

- grid_dtree.best_score_ : 최고 정확도 추출

- grid_dtree.best_estimator_ : 최적의 파라미터가 지정된 estimator을 이용하여 예측을 수행할 수 있음

 

* 새롭게 알게 된 사실

: 모델을 수행할 때마다 최적의 파라미터 값이 변해야 되는데 변하지 않는 것을 알 수 있었다. 이는 코드 안에 random_state 값이 0으로 고정되어져 있었기 때문이고, 값을 변경해주려면 seed 값을 지정해주면 된다는 것을 알 수 있었다.