- 공유 링크 만들기
- 이메일
- 기타 앱
내용
교차검증(Cross-validation)
k-fold 교차검증(Cross-validation)
데이터 샘플이 제한된 경우 학습 모델을 평가하기 위해 사용되는 리샘플링(resampling) 기법으로 데이터셋트를 소그룹으로 분류하여 각 그룹을 평가하는 것으로 분류의 그룹 수인 k라는 매개변수(hyperparameter)를 가집니다.
- 데이터를 무작위로 혼합(shuffle)
- 데이터를 k 그룹으로 분리
- 각 그룹에서
- 훈련(train)과 검정(test) 세트로 분리
- 훈련 세트에 모델을 생성하고 테스트 세트에서 평가
- 평가 점수를 생성
- 모델 평가 점수 비교
k-겹 교차 검증 실행의 결과는 종종 모델 기술 점수의 평균으로 요약됩니다. 표준 편차 또는 표준 오차와 같은 기술 점수의 분산 측정을 포함하는 것도 좋은 방법입니다. 그 분산이 크다면 모델의 과적합, 대표성의 결핍 등의 문제를 고려할 수 있습니다.
k 값을 선택하기 위한 세 가지 일반적인 전술은 다음과 같습니다.
- represtative: 샘플의 훈련/검정 데이터의 크기는 통계적으로 더 큰 데이터 셋트를 대표할 정도로 충분한 크기로 k를 설정합니다.
- k=10: 이 값은 실험적으로 적당한 분산과 낮은 편향을 가진 모델의 추정치를 갖는 수준으로 알려진 값입니다.
- n=n: k 값은 n으로 고정됩니다. 여기서 n은 각 테스트 샘플에 홀드아웃 데이터셋에 사용할 기회를 주기 위한 데이터셋의 크기입니다. 이 접근 방식을 Leave-One-Out 교차 검증이라고 합니다.
import numpy as np import pandas as pd from sklearn.model_selection import KFold, StratifiedKFold, train_test_split from sklearn.datasets import make_classification
np.random.seed(1) x=np.random.randint(100, size=6) x
array([37, 12, 72, 9, 75, 5])
#k=3 np.random.shuffle(x) fold={} j=1 for i in range(2, len(x)+1, 2): fold[f'fold{j}']=x[(i-2):i] j +=1 fold
{'fold1': array([75, 37]), 'fold2': array([12, 5]), 'fold3': array([72, 9])}
위의 결과에서 각 모델은 다음과 같이 분류할 수 있습니다.
Model | train set | test set |
---|---|---|
Model1 | fold1+fold2 | fold3 |
Model2 | fold2+fold3 | fold1 |
Model3 | fold3+fold1 | fold2 |
위 과정은 sklearn.model_selection.KFold(n_splits=5, shuffle=False, random_state=None) 클래스를 적용할 수 있습니다. 이 클래스에 의한 train, test 분리는 split()메서드에 의해 실행됩니다.
kf=KFold(n_splits=3, shuffle=True, random_state=1) for tr, te in kf.split(x): print(f'Train: {x[tr]}, Test:{x[te]}')
Train: [75 5 72 9], Test:[37 12] Train: [37 12 5 9], Test:[75 72] Train: [75 37 12 72], Test:[5 9]
계층화 Kfold
위의 k-fold 교차검증은 학습/검증 분할(train/test split)과 함께 일반적으로 적용할 수 있는 모델 평가 수단입니다. 그러나 데이터의 클래스의 불균형이 심각할 경우 이러한 분할에 의해 특정한 클래스의 데이터가 몰릴 수 있는 가능성이 존재합니다. 이 경우 모델 선택의 실패 가능성이 증가합니다. 대신, 계층화된 훈련-테스트 분할 또는 계층화된 k-겹 교차 검증이라고 하는 클래스 레이블로 샘플링을 계층화하도록 기술을 수정하여 이러한 문제를 개선할 수 있습니다.
정리하면 데이터 세트가 k-fold 교차검증으로 분리되는 경우 균일 확률 분포를 따릅니다. 이는 데이터 전체에 클래스의 분포가 불균일 한 경우 각 그룹에 모든 클래스가 균일하게 포함된다고 가정할 수 없습니다.
X,y=make_classification(n_samples=1000, n_classes=2, weights=[0.99, 0.01], flip_y=0, random_state=1) np.unique(y, return_counts=True)
(array([0, 1]), array([990, 10]))
kf=KFold(n_splits=5, shuffle=True, random_state=1) mod=[] re=pd.DataFrame() n=1 for tr_r, te_r in kf.split(X): xtr, xte=X[tr_r], X[te_r] ytr, yte=y[tr_r], y[te_r] re1=pd.DataFrame([(len(ytr)-ytr.sum())/len(ytr), ytr.sum()/len(ytr), (len(yte)-yte.sum())/len(yte), yte.sum()/len(yte)]).T re=pd.concat([re, re1]) mod.append('group'+str(n)) n +=1 re.index=mod re.columns=['ytr=0','ytr=1','yte=0','yte=1'] re
ytr=0 | ytr=1 | yte=0 | yte=1 | |
---|---|---|---|---|
group1 | 0.98875 | 0.01125 | 0.995 | 0.005 |
group2 | 0.99125 | 0.00875 | 0.985 | 0.015 |
group3 | 0.99250 | 0.00750 | 0.980 | 0.020 |
group4 | 0.98750 | 0.01250 | 1.000 | 0.000 |
group5 | 0.99000 | 0.01000 | 0.990 | 0.010 |
위 결과는 각 그룹의 0, 1에 대한 비율의 변동이 관찰됩니다. 이것은 동일한 조건에서 모델을 평가할 수 없다는 것을 나타냅니다. 반면 계층화 Kfold의 경우 각 그룹의 라벨의 비율을 균등하게 분배합니다.
이 계층화KFold는 sklearn.model_selection.StratifiedGroupKFold(n_splits=5, shuffle=False, random_state=None)
클래스를 적용할 수 있습니다. 이 클래스에 의한 train, test 분리는 .split()
메서드에 의해 실행됩니다.
Skf=StratifiedKFold(n_splits=5, shuffle=True, random_state=1) mod=[] reS=pd.DataFrame() n=1 for tr_r, te_r in Skf.split(X, y): xtr, xte=X[tr_r], X[te_r] ytr, yte=y[tr_r], y[te_r] reS1=pd.DataFrame([(len(ytr)-ytr.sum())/len(ytr), ytr.sum()/len(ytr), (len(yte)-yte.sum())/len(yte), yte.sum()/len(yte)]).T reS=pd.concat([reS, reS1]) mod.append('group'+str(n)) n +=1 reS.index=mod reS.columns=['ytr=0','ytr=1','yte=0','yte=1'] reS
ytr=0 | ytr=1 | yte=0 | yte=1 | |
---|---|---|---|---|
group1 | 0.99 | 0.01 | 0.99 | 0.01 |
group2 | 0.99 | 0.01 | 0.99 | 0.01 |
group3 | 0.99 | 0.01 | 0.99 | 0.01 |
group4 | 0.99 | 0.01 | 0.99 | 0.01 |
group5 | 0.99 | 0.01 | 0.99 | 0.01 |
훈련, 검증세트 분리에 계층화 적용
훈련과 검증 세트의 분리시 계층화(stratify)는 train_test_split()
함수의 인수 stratify에 의해 실행할 수 있습니다. 이 인수의 기본값은 None 입니다. None이 아니면 계층화가 실행됩니다.
xtr, xte, ytr, yte=train_test_split(X, y, test_size=0.3, random_state=2) ytrN=np.unique(ytr, return_counts=True)[0] yteN=np.unique(yte, return_counts=True)[0] print(f'train 0: {len(ytr[ytr==0])/len(ytr)}, 1: {len(ytr[ytr==1])/len(ytr)}') print(f'test 0: {len(yte[yte==0])/len(yte)}, 1: {len(yte[yte==1])/len(yte)}')
train 0: 0.9914285714285714, 1: 0.008571428571428572 test 0: 0.9866666666666667, 1: 0.013333333333333334
xtr, xte, ytr, yte=train_test_split(X, y, test_size=0.3, random_state=2, stratify=y) ytrN=np.unique(ytr, return_counts=True)[0] yteN=np.unique(yte, return_counts=True)[0] print(f'train 0: {len(ytr[ytr==0])/len(ytr)}, 1: {len(ytr[ytr==1])/len(ytr)}') print(f'test 0: {len(yte[yte==0])/len(yte)}, 1: {len(yte[yte==1])/len(yte)}')
train 0: 0.99, 1: 0.01 test 0: 0.99, 1: 0.01
댓글
댓글 쓰기