2019년 1월 20일 일요일

scikit-learn 이용한 (cross-validation) 교차 검증 iterators StratifiedKFold, KFold 사용법


교차 검증 반복자(iterators) 로서 KFold, StratifiedKFold를 많이 사용합니다.
비슷하면서도 다른점 있습니다.
https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation

0. 교차 검증 반복자(iterators)란

교차 유효성 검사 전략에 따라 데이터 집합을 생성하는 데 사용할 수 있는 인덱스를 생성하는 도구 입니다.
https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation-iterators

1. KFold

먼저 KFold 입니다.
그림을 보면 4일때 아래와 같은 그림 형태로 Testing set과 Traing set으로 나뉩니다.
https://scikit-learn.org/stable/modules/cross_validation.html#k-fold
../_images/sphx_glr_plot_cv_indices_0041.png

소스

소스로 구현하면 아래와 같습니다.

import numpy as np
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import KFold

X=np.array([
    [ 1, 2, 3, 4],
    [11,12,13,14],
    [21,22,23,24],
    [31,32,33,34],
    [41,42,43,44],
    [51,52,53,54],
    [61,62,63,64],
    [71,72,73,74]
])

y=np.array([0,0,0,0,0,0,0,0])

kfold = KFold(n_splits=4,random_state=0,shuffle=False)
print(X.shape, y.shape)

print("\nKFold**************")
for train_index, validate_index in kfold.split(X):
    print("train index:", train_index, "validate index:", validate_index)
    X_train, X_validate = X[train_index], X[validate_index]
    y_train, y_validate = y[train_index], y[validate_index]
    print("train data")
    print(X_train, y_train)
    print("validate data")
    print(X_validate, y_validate)

실행결과

(8, 4) (8,)

KFold**************
train index: [2 3 4 5 6 7] validate index: [0 1]
train data
[[21 22 23 24]
 [31 32 33 34]
 [41 42 43 44]
 [51 52 53 54]
 [61 62 63 64]
 [71 72 73 74]] [0 0 0 0 0 0]
validate data
[[ 1  2  3  4]
 [11 12 13 14]] [0 0]
train index: [0 1 4 5 6 7] validate index: [2 3]
train data
[[ 1  2  3  4]
 [11 12 13 14]
 [41 42 43 44]
 [51 52 53 54]
 [61 62 63 64]
 [71 72 73 74]] [0 0 0 0 0 0]
validate data
[[21 22 23 24]
 [31 32 33 34]] [0 0]
train index: [0 1 2 3 6 7] validate index: [4 5]
train data
[[ 1  2  3  4]
 [11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]
 [61 62 63 64]
 [71 72 73 74]] [0 0 0 0 0 0]
validate data
[[41 42 43 44]
 [51 52 53 54]] [0 0]
train index: [0 1 2 3 4 5] validate index: [6 7]
train data
[[ 1  2  3  4]
 [11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]
 [41 42 43 44]
 [51 52 53 54]] [0 0 0 0 0 0]
validate data
[[61 62 63 64]
 [71 72 73 74]] [0 0]

소스 설명

아래 함수에 의해 나누는 수치를 결정합니다.
kfold = KFold(n_splits=4,random_state=0,shuffle=False)
kfold.split(X) 함수에 의해 나뉘어 집니다.


2. StratifiedKFold

비슷하면서도 다릅니다.
https://scikit-learn.org/stable/modules/cross_validation.html#stratified-k-fold
아래 그림에서 보면 계층적으로 나뉩니다.
../_images/sphx_glr_plot_cv_indices_0071.png
나뉠때 정보가 필요하기 때문에 인자로 y를 추가로 받습니다.
다음은 예제 입니다.

소스


import numpy as np
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import KFold

X=np.array([
    [ 1, 2, 3, 4],
    [11,12,13,14],
    [21,22,23,24],
    [31,32,33,34],
    [41,42,43,44],
    [51,52,53,54],
    [61,62,63,64],
    [71,72,73,74]
])

y=np.array([0,0,0,0,0,0,0,0])

stratifiedkfold = StratifiedKFold(n_splits=4,random_state=0,shuffle=False)
print(X.shape, y.shape)

print("\nStratifiedKFold**************")
for train_index, validate_index in stratifiedkfold.split(X,y):
    print("train index:", train_index, "validate index:", validate_index)
    X_train, X_validate = X[train_index], X[validate_index]
    y_train, y_validate = y[train_index], y[validate_index]
    print("train data")
    print(X_train, y_train)
    print("validate data")
    print(X_validate, y_validate)

결과

(8, 4) (8,)

StratifiedKFold**************
train index: [2 3 4 5 6 7] validate index: [0 1]
train data
[[21 22 23 24]
 [31 32 33 34]
 [41 42 43 44]
 [51 52 53 54]
 [61 62 63 64]
 [71 72 73 74]] [0 0 0 0 0 0]
validate data
[[ 1  2  3  4]
 [11 12 13 14]] [0 0]
train index: [0 1 4 5 6 7] validate index: [2 3]
train data
[[ 1  2  3  4]
 [11 12 13 14]
 [41 42 43 44]
 [51 52 53 54]
 [61 62 63 64]
 [71 72 73 74]] [0 0 0 0 0 0]
validate data
[[21 22 23 24]
 [31 32 33 34]] [0 0]
train index: [0 1 2 3 6 7] validate index: [4 5]
train data
[[ 1  2  3  4]
 [11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]
 [61 62 63 64]
 [71 72 73 74]] [0 0 0 0 0 0]
validate data
[[41 42 43 44]
 [51 52 53 54]] [0 0]
train index: [0 1 2 3 4 5] validate index: [6 7]
train data
[[ 1  2  3  4]
 [11 12 13 14]
 [21 22 23 24]
 [31 32 33 34]
 [41 42 43 44]
 [51 52 53 54]] [0 0 0 0 0 0]
validate data
[[61 62 63 64]
 [71 72 73 74]] [0 0]

소스 설명

아래 부분은 KFold와 동일합니다.
stratifiedkfold = StratifiedKFold(n_splits=4,random_state=0,shuffle=False)
stratifiedkfold.split(X,y): y값을 추가 인자로 받습니다.

주의점

사용시 주의해야 할점이 있습니다.
간혹 아래와 같은 에러가 발생하는 경우가 있습니다.
ValueError: n_splits=XX cannot be greater than the number of members in each class.

에러 발생 예제

y=np.array([1,2,3,4,5,6,0,0])
print("\nStratifiedKFold**************")
for train_index, validate_index in stratifiedkfold.split(X,y):
    print("train index:", train_index, "validate index:", validate_index)
    X_train, X_validate = X[train_index], X[validate_index]
    y_train, y_validate = y[train_index], y[validate_index]
    print("train data")
    print(X_train, y_train)
    print("validate data")
    print(X_validate, y_validate)

ValueError: n_splits=4 cannot be greater than the number of members in each class.

사유

y 입력 값을 보면 값 범위가 여러개입니다.(7개 : 0,1,2,3,4,5,6) 우리가 원하는 n_splits=4개로 나누고자 할때 문제가 있어서 오류를 발생하는것입니다. 해결을 위해서는 n_splits 수치를 올려주던가, KFold를 써야 합니다.

참조 링크

https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.StratifiedKFold.html
https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation
https://scikit-learn.org/stable/modules/cross_validation.html#cross-validation-iterators
https://scikit-learn.org/stable/modules/cross_validation.html#k-fold
https://scikit-learn.org/stable/modules/cross_validation.html#stratified-k-fold



댓글 1개:

  1. 안녕하세요. 제가 마지막 n_splits관련 오류를 겪고 있는데 도와주실 수 있으신가요? ㅠㅠ 해결법이 안보입니다.

    답글삭제