Skip to content

train_test_split 사용하기.

ML에서 Test set은 training이 끝난 모델의 generalization error가 어느정도인지를 가늠하기 위해 반드시 필요함.

  • overfitting이 쉽게 되는 high capacity를 가진 model일수록 test-set에 의한 검증결과가 반드시 필요.
    • overfitting이 되기 쉬운 model은 training dataset에서는 매우 높은 performance를 보임.
  • population의 특징을 잘 나타내는 training dataset과 test dataset이 필요함.
    • imbalanced class등의 dataset에서는 stratified sampling 등을 수행해야함.

Scikit-Learn 라이브러리의 model_selection 모듈에서 train_test_split 함수를 제공함으로서 training dataset과 test dataset을 쉽게 나눌 수 있도록 도와줌.

X_train, X_test, y_train, y_test = sklearn.model_selection.train_test_split(
    X_data,
    y_data,
    test_size = 0.25,  # the ratio of test dataset
    train_size = 0.75, # the ratio of training dataset
    shuffle = True,    # 데이터를 분리하기 전에 섞을지(shuffle)를 결정
    random_state = 23, # int.  the seed value of the pseudo random shuffling.
    stratify = y_data, # array-like. 각 stratum 의 비율이 일정하도록 
                       # test와 train을 나누는데, strata를 나누기 위한 기준이 되는 array.
)

다음 코드는 iris dataset을 7:3으로 training dataset과 test dataset으로 나누고, training dataset으로 Decision Tree Classifier로 훈련을 하고, test dataset으로 훈련된 model의 generalization performance를 accuracy로 살펴본다.

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

full_data = load_iris()

X_train, X_test, y_train, y_test = train_test_split(full_data.data.values,
                                                    full_data.target.values,
                                                    test_size=0.3, 
                                                    shuffle=True,
                                                    random_state = 23
                                                    )

clf = DecisionTreeClassifier()
clf.fit(X_train, y_train)

pred = clf.predict(X_test)

print(f'The accuracy of classifier : {accuracy_score(y_test, pred)}')
  • Decision Tree를 사용하기 때문에 쉽게 overfitting됨.
  • predict 의 경우 성능이 train에 비해 매우 떨어짐.

Stratified Sampling

training dataset이나 test dataset은 모두 population 의 특징을 잘 반영하고 있어야 한다.

  • 전체 집합을 population이라고 부름.
  • 원래는 모든 sample을 가진 population으로 훈련을 해야하지만 (전수조사 등을 생각해보라)
  • 그것은 불가능하므로 해당 특성을 충분히 반영한 representative subset을 뽑아서 훈련 및 검증을 하게 됨

iris dataset에서 population을 sklearn에서 제공하는 150개라고 가정을 하자 (가용한 sample의 전체집합 = population).
살펴보면 이들은 크게 3가지 종류의 target을 가지고 있고, 각 target에 속한 sample수가 50개로 모두 같다.
population을 나누는 같은 성질의 subgroup들을 strata라고 부르는데, 각각의 stratum이 전체 갯수에 대해 차지하고 있는 비율은 population, training dataset, test dataset 모두에서 일정 해야 한다.

  • 일반적으로 데이터의 수가 매우 많고, 실제 각 stratum의 수가 같은 경우에는 random sampling을 해도 각 stratum의 수가 비슷하게 유지된다.
  • 하지만, 특정 stratum의 수가 매우 적은 imbalanced data인 경우나, sample의 수가 매우 적은 경우에는 random sampling으로는 이들 비율을 일정하게 유지하지 못한다.
  • 운이 나쁘면, test set에 특정 stratum이 전혀 없는 경우 가 발생할 수도 있다.

이를 방지하기 위해서 각각의 stratum의 비율이 유지되도록 training dataset과 test dataset을 나누는 방법을 sklearn.model_selection 모듈의 train_test_split에서 제공하며, 이를 가르켜 stratified sampling 이라고 부른다.

iris dataset에서 각 target (붓꽃의 종류)을 stratum이라고 보고, 이들의 비율이 원래 full dataset과 같게 training dataset과 test dataset이 나누어지게 하려면, train_test_split 함수의 stratified 파라메터에 target 의 정보를 가진 array를 argument로 넘겨주면 된다.

X_train, X_test, y_train, y_test  = train_test_split(
    full_data.data, 
    full_data.target,
    test_size = 0.3,
    stratify=full_data.target,
    shuffle=True,
    random_state=23
)

전체 150개 sample의 30%는 45개이므로, test dataset은 45개의 sample로 구성되며, 3종류 target에 각각 속하는 샘플들 15개씩으로 test dataset이 구성된다.

주의할 점은 지나치게 많은 strata로 나뉘게 될 경우, 특정 stratum에 속한 sample의 갯수가 지나치게 작아지게 될 수 있기 때문에 피해야 한다. 즉, 각 stratum에 적절한 수의 샘플이 놓이도록 처리해야 한다.


주의사항

  • test dataset이나 training dataset이나 모두 population의 representative subset이어야 한다.
  • ML의 특징상 어느 정도 이상의 training dataset이 없으면 제대로 훈련이 되지 않으므로 training dataset이 훈련에 지장이 없을 정도의 sample 수를 갖추어야 한다.
  • 하지만, test의 결과인 generalization error의 신뢰도를 확보하기 위해서는 test dataset도 지나치게 적은 수가 되서는 안된다.
  • imbalanced dataset에서는 가급적 stratified sampling을 수행해서 test dataset과 training dataset을 나누어야 한다.
  • 지나치게 많은 수의 strata를 가지도록 해선 안된다.

Test dataset은 나누고 난 이후에는 마지막으로 generalization performance를 측정하는 경우 외에는 접근할 필요가 없다. 우선 이렇게 나누고 난 이후, training dataset에 대해 Exploratory Data Analysis (EDA)를 수행하는게 일반적이다.

Stratified sampling은 classification에서 기본으로 사용되어야 함(cross validation의 경우도 마찬가지). 하지만, regression의 경우에는 그 중요도가 떨어진다. (반드시 사용해야할 필요는 없다) 연속된 변수 자체를 맞추어야 하기 때문에 label값에 대한 분포가 training에 미치는 영향이 classification보다는 떨어지기 때문이다.


Exploratory Data Analysis (EDA)
적절한 모델 등을 선택하기 위해서 data에 대한 이해가 필요하기 때문에 data를 살펴보는 과정임.
model training 등의 과정 전에 data에 대한 insight를 얻기 위해 수행되는 과정.

split 객체 사용하기.

train_test_split 함수와 달리, split 객체들로 처리하는 방법은 다음에 소개하는 cross validation과 연계가 가능함.

sklearn.model_selection.StratifiedKFold
n_splits에 할당하는 argument로 CV에서 사용할 number of folds를 결정한다. 만약 1을 사용하면, train_test_split함수와 같은 역할을 수행하게 된다(물론 이후 split를 호출). k-Fold기법을 구현한 것으로 test dataset으로 지정된 index들이 겹쳐지지 않는다.
sklearn.model_selection.StratifiedShuffleSplit
n_splits에 할당하는 argument에 따라 CV에서 이루어질 evaluation이 몇 번 이루어질지를 결정한다. k-Fold와 달리 램덤하게 test dataset이 결정되며 test에 선택된 index들이 겹칠 수 있다. k-Fold에서는 subset이 나누어지는 구조이기때문에 test dataset이 겹칠 수가 없다(모든 샘플은 test dataset이 될 수 있는 것은 오직 하나의 fold로만 한정됨).

관련 자료.