인공지능 공부/머신러닝

2021-04-22 머신러닝 완벽가이드 교차 검증

내장된 예제 데이터 세트
from sklearn.datasets import load_iris

iris_data = load_iris()
print(type(iris_data))
<class 'sklearn.utils.Bunch'>
keys = iris_data.keys()
print('붓꽃 데이터 세트의 키들:' ,keys)
붓꽃 데이터 세트의 키들: dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
print('\n feature_names 의 type:',type(iris_data.feature_names))
print(' feature_names 의 shape:',len(iris_data.feature_names))
print(iris_data.feature_names)

print('\n target_names의 type', type(iris_data.target_names))
print(' target_names의 shape:', len(iris_data.target_names))
print(iris_data.target_names)

print('\n data의 type:', type(iris_data.data))
print(' data의 shape:',len(iris_data.data))
print(iris_data.data)

print('\n target의 type:', type(iris_data.target))
print(' target의 shape:', len(iris_data.target))
print(iris_data.target)
 feature_names 의 type: <class 'list'>
 feature_names 의 shape: 4
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

 target_names의 type <class 'numpy.ndarray'>
 target_names의 shape: 3
['setosa' 'versicolor' 'virginica']

 data의 type: <class 'numpy.ndarray'>
 data의 shape: 150
[[5.1 3.5 1.4 0.2]
 [4.9 3.  1.4 0.2]
 [4.7 3.2 1.3 0.2]
 [4.6 3.1 1.5 0.2]
 [5.  3.6 1.4 0.2]
 [5.4 3.9 1.7 0.4]
 [4.6 3.4 1.4 0.3]
 [5.  3.4 1.5 0.2]
 [4.4 2.9 1.4 0.2]
 [4.9 3.1 1.5 0.1]
 [5.4 3.7 1.5 0.2]
 [4.8 3.4 1.6 0.2]
 [4.8 3.  1.4 0.1]
 [4.3 3.  1.1 0.1]
 [5.8 4.  1.2 0.2]
 [5.7 4.4 1.5 0.4]
 [5.4 3.9 1.3 0.4]
 [5.1 3.5 1.4 0.3]
 [5.7 3.8 1.7 0.3]
 [5.1 3.8 1.5 0.3]
 [5.4 3.4 1.7 0.2]
 [5.1 3.7 1.5 0.4]
 [4.6 3.6 1.  0.2]
 [5.1 3.3 1.7 0.5]
 [4.8 3.4 1.9 0.2]
 [5.  3.  1.6 0.2]
 [5.  3.4 1.6 0.4]
 [5.2 3.5 1.5 0.2]
 [5.2 3.4 1.4 0.2]
 [4.7 3.2 1.6 0.2]
 [4.8 3.1 1.6 0.2]
 [5.4 3.4 1.5 0.4]
 [5.2 4.1 1.5 0.1]
 [5.5 4.2 1.4 0.2]
 [4.9 3.1 1.5 0.2]
 [5.  3.2 1.2 0.2]
 [5.5 3.5 1.3 0.2]
 [4.9 3.6 1.4 0.1]
 [4.4 3.  1.3 0.2]
 [5.1 3.4 1.5 0.2]
 [5.  3.5 1.3 0.3]
 [4.5 2.3 1.3 0.3]
 [4.4 3.2 1.3 0.2]
 [5.  3.5 1.6 0.6]
 [5.1 3.8 1.9 0.4]
 [4.8 3.  1.4 0.3]
 [5.1 3.8 1.6 0.2]
 [4.6 3.2 1.4 0.2]
 [5.3 3.7 1.5 0.2]
 [5.  3.3 1.4 0.2]
 [7.  3.2 4.7 1.4]
 [6.4 3.2 4.5 1.5]
 [6.9 3.1 4.9 1.5]
 [5.5 2.3 4.  1.3]
 [6.5 2.8 4.6 1.5]
 [5.7 2.8 4.5 1.3]
 [6.3 3.3 4.7 1.6]
 [4.9 2.4 3.3 1. ]
 [6.6 2.9 4.6 1.3]
 [5.2 2.7 3.9 1.4]
 [5.  2.  3.5 1. ]
 [5.9 3.  4.2 1.5]
 [6.  2.2 4.  1. ]
 [6.1 2.9 4.7 1.4]
 [5.6 2.9 3.6 1.3]
 [6.7 3.1 4.4 1.4]
 [5.6 3.  4.5 1.5]
 [5.8 2.7 4.1 1. ]
 [6.2 2.2 4.5 1.5]
 [5.6 2.5 3.9 1.1]
 [5.9 3.2 4.8 1.8]
 [6.1 2.8 4.  1.3]
 [6.3 2.5 4.9 1.5]
 [6.1 2.8 4.7 1.2]
 [6.4 2.9 4.3 1.3]
 [6.6 3.  4.4 1.4]
 [6.8 2.8 4.8 1.4]
 [6.7 3.  5.  1.7]
 [6.  2.9 4.5 1.5]
 [5.7 2.6 3.5 1. ]
 [5.5 2.4 3.8 1.1]
 [5.5 2.4 3.7 1. ]
 [5.8 2.7 3.9 1.2]
 [6.  2.7 5.1 1.6]
 [5.4 3.  4.5 1.5]
 [6.  3.4 4.5 1.6]
 [6.7 3.1 4.7 1.5]
 [6.3 2.3 4.4 1.3]
 [5.6 3.  4.1 1.3]
 [5.5 2.5 4.  1.3]
 [5.5 2.6 4.4 1.2]
 [6.1 3.  4.6 1.4]
 [5.8 2.6 4.  1.2]
 [5.  2.3 3.3 1. ]
 [5.6 2.7 4.2 1.3]
 [5.7 3.  4.2 1.2]
 [5.7 2.9 4.2 1.3]
 [6.2 2.9 4.3 1.3]
 [5.1 2.5 3.  1.1]
 [5.7 2.8 4.1 1.3]
 [6.3 3.3 6.  2.5]
 [5.8 2.7 5.1 1.9]
 [7.1 3.  5.9 2.1]
 [6.3 2.9 5.6 1.8]
 [6.5 3.  5.8 2.2]
 [7.6 3.  6.6 2.1]
 [4.9 2.5 4.5 1.7]
 [7.3 2.9 6.3 1.8]
 [6.7 2.5 5.8 1.8]
 [7.2 3.6 6.1 2.5]
 [6.5 3.2 5.1 2. ]
 [6.4 2.7 5.3 1.9]
 [6.8 3.  5.5 2.1]
 [5.7 2.5 5.  2. ]
 [5.8 2.8 5.1 2.4]
 [6.4 3.2 5.3 2.3]
 [6.5 3.  5.5 1.8]
 [7.7 3.8 6.7 2.2]
 [7.7 2.6 6.9 2.3]
 [6.  2.2 5.  1.5]
 [6.9 3.2 5.7 2.3]
 [5.6 2.8 4.9 2. ]
 [7.7 2.8 6.7 2. ]
 [6.3 2.7 4.9 1.8]
 [6.7 3.3 5.7 2.1]
 [7.2 3.2 6.  1.8]
 [6.2 2.8 4.8 1.8]
 [6.1 3.  4.9 1.8]
 [6.4 2.8 5.6 2.1]
 [7.2 3.  5.8 1.6]
 [7.4 2.8 6.1 1.9]
 [7.9 3.8 6.4 2. ]
 [6.4 2.8 5.6 2.2]
 [6.3 2.8 5.1 1.5]
 [6.1 2.6 5.6 1.4]
 [7.7 3.  6.1 2.3]
 [6.3 3.4 5.6 2.4]
 [6.4 3.1 5.5 1.8]
 [6.  3.  4.8 1.8]
 [6.9 3.1 5.4 2.1]
 [6.7 3.1 5.6 2.4]
 [6.9 3.1 5.1 2.3]
 [5.8 2.7 5.1 1.9]
 [6.8 3.2 5.9 2.3]
 [6.7 3.3 5.7 2.5]
 [6.7 3.  5.2 2.3]
 [6.3 2.5 5.  1.9]
 [6.5 3.  5.2 2. ]
 [6.2 3.4 5.4 2.3]
 [5.9 3.  5.1 1.8]]

 target의 type: <class 'numpy.ndarray'>
 target의 shape: 150
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2]
Model Selection 모듈 소개
학습 테스트 데이터 세트 분리 train_test_split
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
iris = load_iris()
dt_clf = DecisionTreeClassifier()
train_data = iris.data
train_label = iris.target
dt_clf.fit(train_data, train_label)

#학습데이터로 예측수행 
pred = df_clf.predict(train_data)
print('예측정확도:',accuracy_score(train_label, pred))

### 학습데이터와 테스터 데이터를 분리하지 않으면 ?
#해당 테스트 데이터를 먼저 학습해버리기 떄문에 모의고사를 한번 보고 다시 시험을 보게되기에 
예측정확도: 0.9866666666666667
# test_size : 전체 데이터에서 테스트 데이터 세트 크기 지정 디폴트 0.25 25%
# train_size : 전체사이즈에서 얼마나 샘플링 할 것인가
# shuffle: 테스트를 분리하기전 미리 섞을 겄인가 디폴트는 True
# random_state : 호출 할떄마다 학습과 테스트 데이터를 분리하기위한 난수를 생성하는 것
# train_test_split 반환 값은 튜플의 형태이다. 
# 1.학습용 데이터의 피처데이터 세트, 테스트용 데이터의 피처데이터 , 학습용 레이블 세트, 테스트용 레이블 세트
from sklearn.model_selection import train_test_split
dt_clf = DecisionTreeClassifier
iris_data= load_iris()

X_train, X_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target, test_size=0.3, random_state = 121)
df_clf.fit(X_train, y_train)
pred = df_clf.predict(X_test)
print('예측 정확도: {0:4f}'.format(accuracy_score(y_test, pred)))
예측 정확도: 0.955556
교차 검증
과적합 될 수 있는 문제를 해결하기 위해서 먼저 교차검증은 실제 모델이 학습데이터에만 과도하게 최적화되어서 실제 테스트 데이터에는
최적의 성능을 할 수 없는 것을 막기위해서
본고사를 보기전에 모의고사를 여러번 보는 것이다. 즉 ML은 데이터에 기반합니다. 그리고 데이터는 이상치, 분포도, 다양한 속성값, 피처 중요도 등 ML에 영향을 미치는 요소를 가지고 있다. 특정 ML알고리즘에서 최적으로 동작할 수 있도록 데이터를 선별해 학습
교차 검증은 이러한 편증을 막기 위해서 별도의 여러 세트로 구성된 학습데이터와 검증 데이터 세트를 만들고 학습과 평가를 함
학습데이터를 다시 분할하여 학습데이터 세트 + 검증 데이터 세트
K폴드 교차 검증
K폴드 교차 검증은 가장 보편적으로 사용되는 교차검증 기법이다. 폴드 세트를 만들어서 K번만큼 각 폴트 세트에 학습과 검증평가를 함
from sklearn.model_selection import KFold
import numpy as np

features = iris.data
label = iris.target

dt_clf = DecisionTreeClassifier(random_state=15)

#5개의 폴드 세트로 분리하는 Kfold객체와 폴드 세트별 정확도를 담을 리스트 객체 생성
kfold = KFold(n_splits=5)
cv_accuracy = []
print('붓꽃 데이터 세트 크기:', feature.shape[0])
붓꽃 데이터 세트 크기: 150
n_iter = 0;
#Kfold 객체의 split()호출 하면 폴드 별  학습용, 검증용 테스트의 로우 인덱스를 array로 변환

for train_index, test_index in kfold.split(features):
    #kforld.split()으로 반환된 인덱스를 이용해 학습용, 검증용 테스트 데이터 추출
    
    X_train, X_test = features[train_index], features[test_index]
    y_train, y_test = label[train_index], label[test_index]
    
    
    #학습 및 예측
    dt_clf.fit(X_train, y_train)
    pred = dt_clf.predict(X_test)
    n_iter +=1
    
    #반복 시마다 정확도 측정
    accuracy = np.round(accuracy_score(y_test, pred),4)
    train_size = X_train.shape[0]
    test_size = X_test.shape[0]
    
    
    accuracy = np.round(accuracy_score(y_test, pred),4)
    train_size = X_train.shape[0]
    test_size = X_test.shape[0]
    
    print('#{0} 교차 검증 정확도 :{1}, 학습데이터 크기:{2}, 검증 데이터 크기:{3}'.format(n_iter, accuracy, train_size, test_size))
    print('#{0} 검증 세트 인덱스 :{1}'.format(n_iter, test_index))
    cv_accuracy.append(accuracy)
    
    #개별 iteration별 정확도를 합하여 평균 정확도 계산
    print('\n##평균 검증 정확도:',np.mean(cv_accuracy))
    
    
    
#1 교차 검증 정확도 :1.0, 학습데이터 크기:120, 검증 데이터 크기:30
#1 검증 세트 인덱스 :[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 24 25 26 27 28 29]

##평균 검증 정확도: 1.0
#2 교차 검증 정확도 :0.9667, 학습데이터 크기:120, 검증 데이터 크기:30
#2 검증 세트 인덱스 :[30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
 54 55 56 57 58 59]

##평균 검증 정확도: 0.98335
#3 교차 검증 정확도 :0.9, 학습데이터 크기:120, 검증 데이터 크기:30
#3 검증 세트 인덱스 :[60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
 84 85 86 87 88 89]

##평균 검증 정확도: 0.9555666666666666
#4 교차 검증 정확도 :0.9333, 학습데이터 크기:120, 검증 데이터 크기:30
#4 검증 세트 인덱스 :[ 90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107
 108 109 110 111 112 113 114 115 116 117 118 119]

##평균 검증 정확도: 0.95
#5 교차 검증 정확도 :0.7333, 학습데이터 크기:120, 검증 데이터 크기:30
#5 검증 세트 인덱스 :[120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
 138 139 140 141 142 143 144 145 146 147 148 149]

##평균 검증 정확도: 0.9066599999999999
Stratified K 폴드
stratified K폴드는 불균형한 분포도를 가진 레이블 데이터 집합을 위한 K폴드 방식

레이블이 특이하게 많거나 매우 적어서 값의 분포가 한쪽으로 치우는 것을 말합니다.

테스트데이터 세트에 제대로 레이블의 분포를 할 수없을때 ( 대출사기 등 1건 2건 이런 이상치가 작을때)

Stratified K 폴드는 이처럼 K폴드가 레이블데이터 분포 분배를 못할 때

import pandas as pd
iris = load_iris()
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)
iris_df['label'] = iris.target
iris_df['label'].value_counts()
iris_df
sepal length (cm)	sepal width (cm)	petal length (cm)	petal width (cm)	label
0	5.1	3.5	1.4	0.2	0
1	4.9	3.0	1.4	0.2	0
2	4.7	3.2	1.3	0.2	0
3	4.6	3.1	1.5	0.2	0
4	5.0	3.6	1.4	0.2	0
...	...	...	...	...	...
145	6.7	3.0	5.2	2.3	2
146	6.3	2.5	5.0	1.9	2
147	6.5	3.0	5.2	2.0	2
148	6.2	3.4	5.4	2.3	2
149	5.9	3.0	5.1	1.8	2
150 rows × 5 columns

#이렇게 할 경우 Kfold의 학습데이터셋에서는 검증데이터셋과 달라지게 됨

kfold = KFold(n_splits=3)
n_iter =0
for train_index, test_index in kfold.split(iris_df):
    n_iter +=1
    label_train = iris_df['label'].iloc[train_index]
    label_test = iris_df['label'].iloc[test_index]
    
    print('##교차 검증:{0}'.format(n_iter))
    print('학습 레이블 데이터 분포:\n', label_train.value_counts())
    print('검증 레이블 데이터 분포:\n', label_test.value_counts())
    
##교차 검증:1
학습 레이블 데이터 분포:
 2    50
1    50
Name: label, dtype: int64
검증 레이블 데이터 분포:
 0    50
Name: label, dtype: int64
##교차 검증:2
학습 레이블 데이터 분포:
 2    50
0    50
Name: label, dtype: int64
검증 레이블 데이터 분포:
 1    50
Name: label, dtype: int64
##교차 검증:3
학습 레이블 데이터 분포:
 1    50
0    50
Name: label, dtype: int64
검증 레이블 데이터 분포:
 2    50
Name: label, dtype: int64
#이러한 부분의 폴드의 교차검증을 막고자 데이터의 분포를 맞추기위해 
#StratifiedFold 사용
from sklearn.model_selection import StratifiedKFold

skf = StratifiedKFold(n_splits=3)
n_iter= 0

for train_index, test_index in skf.split(iris_df, iris_df['label']):
    n_iter += 1
    label_train = iris_df['label'].iloc[test_index]
    label_test = iris_df['label'].iloc[test_index]
    print('##교차 검증:{0}'.format(n_iter))
    print('학습 레이블 데이터 분포:\n',label_train.value_counts())
    print('검증 레이블 데이터 분포:\n',label_test.value_counts())
##교차 검증:1
학습 레이블 데이터 분포:
 1    17
0    17
2    16
Name: label, dtype: int64
검증 레이블 데이터 분포:
 1    17
0    17
2    16
Name: label, dtype: int64
##교차 검증:2
학습 레이블 데이터 분포:
 2    17
0    17
1    16
Name: label, dtype: int64
검증 레이블 데이터 분포:
 2    17
0    17
1    16
Name: label, dtype: int64
##교차 검증:3
학습 레이블 데이터 분포:
 2    17
1    17
0    16
Name: label, dtype: int64
검증 레이블 데이터 분포:
 2    17
1    17
0    16
Name: label, dtype: int64
교차 검증을 보다 간편하게 해보자 - cross_val_score()
from sklearn.model_selection import cross_val_score, cross_validate

iris_data = load_iris()
df_clf = DecisionTreeClassifier(random_state=156)

data = iris_data.data
label = iris_data.target

#성능 지표는 정확도(accuracy), 교차 검증 세트는 3개

scores = cross_val_score(df_clf, data, label, scoring = 'accuracy', cv=3)
print('교차 검증별 정확도:',np.round(scores,4))
print('평균 검증 정확도:',np.round(np.mean(scores),4))
교차 검증별 정확도: [0.98 0.94 0.98]
평균 검증 정확도: 0.9667