Yet Never Lose Faith

- Good to Great , Jim Collins

How To Preprocess Image Data 자세히보기

Deep Learning/[Books] Do it! 정직하게 코딩하며 배우는 딥러닝 입문

[모델 평가] 훈련데이터셋 나누기 (feat.train_test_split())

Kellyyyy 2020. 7. 20. 08:00

 

 

이번 포스팅에서는 머신러닝/딥러닝 모델의 성능평가를 위해 훈련데이터셋을 나누는 이유와 방법에 대해 알아본다.

 


WHY ?

 

훈련데이터세트 나누기

 

   인공지능 모델을 구축하면 실제 상황에 적용하기 전에 성능평가를 진행해야한다. 이때 훈련데이터 세트로 학습된 모델을 다시 훈련 데이터세트로 평가하면 높은 성능이 나올 것이다(과도하게 낙관적으로 일반화 성능이 추정되었다). 그 모델에는 이미 훈련데이터 셋에 맞는 규칙이 반영되었기 때문이다. 이런 문제를 해결하기 위해 훈련 데이터셋을 훈련용 데이터성능평가용 데이터로 나눈 후 성능평가 단계에서는 모델 학습에 이용하지 않은 성능평가용 데이터를 사용한다. 이때 훈련용 데이터를 훈련세트(training set), 성능평가용 데이터를 테스트세트(test set)이라고 한다.

 


CONDITIONS!

 

1. 훈련데이터 세트를 나눌 때는 테스트 세트보다 훈련세트가 더 많아야한다.
2. 훈련 데이터 세트를 나누기 전에 양성, 음성 클래스가 훈련세트나 테스트 세트의 어느 한쪽에 몰리지 않도록 골고루 섞어야 한다.

 

전체 훈련데이터 세트의 양성,음성 클래스의 비율이 훈련세트와 테스트세트에도 동일하게 유지되어야한다. 훈련세트에 한쪽 클래스가 너무 많이 몰리면 모델이 데이터의 패턴을 올바르게 학습하지 못할 것이고, 테스트세트에 한쪽 클래스가 몰린다면 성능을 잘못 측정할 수도 있기 때문이다.

훈련데이터세트의 클래스 비율을 유지하라!

 

위 그림은 전체 훈련데이터 세트의 양성, 음성 클래스의 비율이 2:1인 경우, 제대로 나눠진 경우와 잘못 나눠진 경우를 보여준다. 제대로 나눠진 경우는 각 세트의 클래스 비율이 동일하게 2:1이다. 하지만 잘못 나눠진 경우는 클래스 비율이 망가져있다. 그럼 이제 올바르게 훈련세트와 테스트 세트를 분할하는 방법에 대해서 알아보자.


HOW TO ?

 

# 훈련데이터 세트 세팅
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
x = cancer.data
y = cancer.target

# 훈련데이터 세트 분할
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, stratify=y, test_size=0.2, random_state=42)

 

물론 내가 직접 훈련 데이터 세트를 섞고 나눠도 되지만, 사이킷런에서 그 모든 과정을 한꺼번에 할 수 있는 편리한 함수를 제공하기 때문에 굳이 그럴 필요가 없다. 이 함수를 사용하기 위해서는 먼저 sklearn.model_selection 모듈에서train_test_split() 함수를 import 한다. 그리고 위와 같은 방식으로 함수를 호출하면 되는데, 각 매개 변수가 어떤 것을 의미하는지 살펴보자.

 

① x : 입력데이터

 

y : 타깃데이터

 

stratify = y 

stratify라는 매개변수에 대해 궁금해서 sklearn document를 찾아봤다.

 

 

sklearn train_test_split documentation

 

우선 default 세팅은 None이고, 배열형식으로 세팅했을 때 해당 배열을 클래스 레이블로 사용하여 stratified fashion으로 데이터를 분할한다. 그런데 stratified fashion...? 이게 무슨 뜻이지? 구글 번역기에 돌려봤는데 '계층화된 방식' 이라는데.. 와닿지 않아 추가적으로 구글링을 해봤다. 그러던 중 좋은 설명을 찾아서 첨부한다.

 

 

출처 : stackExchange

 

Stratified sampling은 Random sampling과는 다른 샘플링 방식이다. Stratified sampling는 훈련데이터를 나눌 때 무작위로 샘플링을 하되, original dataset의 클래스 비율이 train, test set에서도 동일하게 유지되는 것을 보장한다는 점이 Random sampling과의 차이점이다. 위 CONDITIONS 섹션에서도 말했듯이, 분류문제에서는 이 비율이 유지되는 것이 굉장히 중요한데, original dataset에서 특정 클래스 비율이 불균형한 경우 stratify 매개변수에 타깃 데이터를 지정하여 호출하면 (어떠한 통계적 기법을 통해서) 이 비율이 유지될 수 있도록 샘플링한다. 

 

이번 포스팅에서는 stratify = y로 지정해봤다. ( cancer 데이터셋의 양성, 음성 클래스 비율은 약 1.7:1인데 startify = y로 지정했을 때가 0.82, 지정하지 않았을 때(None)가 0.83으로 거의 유사한 정확도가 나왔다. 어떨 때 효과가 있는지는 좀 더 사례를 찾아봐야할 것 같다.)

 

 test_size = 0.2

train_test_split()은 기본적으로 훈련데이터 세트를 75:25의 비율로 나눈다. 이 비율을 조정하고 싶을 때는 test_size 매개변수에 테스트 세트의 비율을 전달하면 조절할 수 있다. 여기서는 입력된 데이터 세트의 20%를 테스트 세트로 나누기 위해 0.2를 전달했다.

 

 random_state = 42

train_test_split()는 데이터를 무작위로 섞은 뒤, 데이터 셋을 나눈다. 그래서 함수를 호출할 때마다 다른 결과로 분할이 되는데, random_state를 특정 숫자로 지정하면 항상 동일하게 분할할 수 있다. 실제 상황에서는 거의 필요 없지만, 다른 사람들과 결과를 공유해야하거나 실험결과를 똑같이 재현해야 할 때는 유용하게 쓰인다.


RESULT

 

## 훈련데이터세트의 shape ##
print(x.shape)
# (569,30) 

## 훈련세트, 테스트세트 shape ##
print(x_train.shape, x_test.shape)
# (455,30) (114,30)

## 훈련데이터세트의 클래스 비율 ##
np.unique(y, return_counts = True)
# (array([0,1]), array([212,357]))

## 훈련세트의 클래스 비율 ##
np.unique(y_train, return_counts = True)
# (array([0,1]), array([170,285]))

## 훈련세트의 클래스 비율 ##
np.unique(y_test, return_counts = True)
# (array([0,1]), array([42, 72]))

 

shape 속성을 통해 훈련세트와 테스트세트의 비율을 확인했다. 전체 훈련데이터 세트 569개의 샘플이 훈련세트와 테스트세트에 각각 455개 114개씩 분할되었다. 445:114 = 4:1로, test_size = 0.2로 지정한 대로 제대로 분할되었다. 다음으로 unique 함수를 통해 각 클래스의 비율을 확인했다. 훈련데이터 세트의 클래스 비율은 양성 : 음성 = 357 : 212로, 양성 클래스가 음성클래스보다 약 1.7배 정도 많았다. 훈련세트와 테스트세트의 클래스 비율도 각각 285:170, 72:42로 비율이 그대로 유지되고 있다.

 

이상으로 훈련데이터 세트를 훈련,테스트 세트로 분할해야하는 이유와 방법등을 알아보았다.

 

[Reference.]

도서

- Do it! 정직하게 코딩하며 배우는 딥러닝 입문, 박해선, 이지스퍼블리싱

URL

- https://stats.stackexchange.com/questions/250273/benefits-of-stratified-vs-random-sampling-for-generating-training-data-in-classi

 

Benefits of stratified vs random sampling for generating training data in classification

I would like to know if there are any/some advantages of using stratified sampling instead of random sampling, when splitting the original dataset into training and testing set for classification. ...

stats.stackexchange.com

- https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html?highlight=train_test_split#sklearn.model_selection.train_test_split

 

sklearn.model_selection.train_test_split — scikit-learn 0.23.1 documentation

 

scikit-learn.org