권철민 강사님의 '파이썬 머신러닝 완벽 가이드'을 학습하고 정리한 것입니다. 배우는 중이라 잘못된 내용이 있을 수 있으며 계속해서 보완해 나갈 것입니다. :))
Sklearn 소개
- 파이썬 기반의 다른 머신런닝 패키지도 사이킷런 스타일의 API를 지향할 정도로 쉽고 가장 파이썬 스러운 API 를 제공한다.
- 머신런닝을 위한 매우 다양한 알고리즘과 개발을 위한 편리한 프레임워크와 API 를 제공한다.
- 주로 Numpy와 Scipy 기반 위에서 구축된 라이브러리이다.
붓꽃 데이터를 예측하는 문제를 통해 Sklearn의 사용에 대해서 배운 것을 정리해보고자 한다.
붓꽃 데이터 세트는 sklearn의 내장 예제 데이터셋이며 구성은 이렇게 dictionary 형태로 되어 있다.
데이터 셋을 코드로 살펴보자.
Sklearn 내장 예제 - 붓꽃 데이터
from sklearn.datasets import load_iris
iris_data = load_iris()
print(type(iris_data))
keys = iris_data.keys()
print('붓꽃 데이터 세트의 키들:', keys) #dictionary 형태로 되어있다고 했으니까.
키는 보통 data, target, target_name, feature_names, DESCR로 구성
개별 키가 가리키는 의미는 다음과 같다.
- data는 피처의 데이터 세트
- target은 분류 시 레이블 값, 회귀일 때는 숫자 결괏값 데이터 세트
- target_names는 개별 레이블의 이름
- feature_names는 피처의 이름
- DESCR은 데이터 세트에 대한 설명과 각 피처의 설명
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(' feature_names 의 shape:',len(iris_data.target_names))
print(iris_data.target_names)
print('\n data 의 type:',type(iris_data.data))
print(' data 의 shape:',iris_data.data.shape)
print(iris_data['data'][:5])
print('\n target 의 type:',type(iris_data.target))
print(' target 의 shape:',iris_data.target.shape)
print(iris_data.target[:5])
붓꽃 데이터 세트는 꽃잎의 길이와 너비, 꽃받침의 길이와 너비 feature을 기반으로 폼의 품종을 예측하기 위한 것이다.
정리하면,
- 지도학습 중 분류
- 독립변수(x): 꽃잎의 길이, 너비, 꽃받침의 길이, 너비
- 종속변수(y): 품종( Setosa, Vesicolor, Virginica)
붓꽃 데이터 분류 예측 프로세스는 아래와 같이 이루어 질 수 있다.
1. 데이터 세트 분리: 데이터를 training data와 test data로 분리
2. 모델 학습: training data를 기반을로 ML 알골리즘을 적용하여 모델을 학습
3. 예측 수행: 학습된 ML 모델을 이용해 test data의 분류를 예측
4. 평가: 이렇게 예측된 결과값과 test data의 실제 결괏값을 비교해 ML 모델 성능을 평가
사이킷런을 사용해서 어떻게 구현 할 수 있는지 알아보자.
1) train/test data set 분리
데이터를 training data와 test data로 분리
대표적으로 sklearn.model_selection의 train__test_split() 함수를 사용한다.
앞서 살펴 본 것처럼 iris data의 데이터는 numpy의 ndarray의 형태로 되어있다. 이 경우 아래와 같이 training/test data로 분리 할 수 있다.
1. numpy의 ndarray의 형태의 training/test data로 분리
X_train, X_test, y_test, y_test = train_test_split(iris__data, iris_data.target, test_sizee=0.3, random_state=121)
# test_size: 전체 데이터에서 test data 세트의 크기. 디폴트는 0.25(25%)
# train_size: 전체 데이터에서 training data 세트의 크기.
# shuffle: 데이터를 분리하기 전에 미리 섞을지를 결정. 디폴트는 True
# random_state: 호출시마다 동일한 training/테스트용 데이터 세트를 생성하기 위해 주어지는 난수값. 지정하지 않으면 수행시마다 training/테스트 세트가 달라짐
numpy의 ndarray의 형태 뿐만 아니라 pandas의 DataFrame/Series 형태도 train__test_split() 함수를 통해 training/test data로 분리 할 수 있다.
2. pandas의 DataFrame/Series 형태의 training/test data로 분리
iris_df = pd.DataFrame(iris_data.data, columns = iris_data.feature_names)
iris_df['target'] = iris_data.target
# iris_df.head()
# featrue 데이터셋과 target 데이터셋을 각각 DataFrame으로 만든다.
feature_df = iris_df.iloc[:, :-1]
target_df = iris_df.iloc[:, -1]
X_train, X_test, y_train, y_test = train_test_split(feature_df, target_df, test_size=0.3, random_state=121)
2) 교차 검증 (Cross Validation)
※ Overfitting 개선 방법이 될 수 있음
위에선 데이터를 training/test data로 구성하였다. 그러면 모델 성능 평가를 test data로 진행하게 된다. 이렇게 고정된 test data로 모델 성능을 평가하고, 이 데이터에서만 최적의 성능을 발휘 할 수 있도록 파라미터가 최적화되면 결국 '이' test data 에만 성능이 좋은 과적합된 모델이 만들어진다.
이런 데이터 편증을 막기 위해서 별도의 여러 세트로 구성된 training data 세트와 validation data 세트에서 학습 및 평가를 수행하고,
test data 세트는 모든 학습 및 검증 과정이 끝난 후 최종적으로 성능을 평가할 때 사용하는 것이 교차 검증이다.
그래서 아래의 그림과 같은 flow를 가진다.
1. 교차 검증의 대표적인 방법
① K 폴드 교차 검증
K 폴드 교차 검증은 가장 보편적으로 사용되는 방법이다. Training data를 k개의 데이터 폴드로 분할하고, k번 반복해서 training data와 validation data을 변경해가며(아래의 그림을 보면 이해가 더 쉽다) 로 학습 및 모델 성능 검증 평가를 진행한다. 그리고 이렇게 k 번 검증 평가 결과를 평균하여 k 폴드 평가 결과를 낸다.
# 붓꽃 예측을 위해서 필요한 sklearn 모듈 불러오기
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier #DecisionTree모델을 사용할 것임.
#from sklearn.model_selection import train_test_split
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
#그 외
import pandas as pd
import numpy as np
iris_data = load_iris()
features = iris_data.data
target = iris_data.target
print('붓꽃 데이터 세트 크기:',features.shape[0])
# 5개의 폴드 세트로 분리하는 KFold 객체와 폴드 세트별 정확도를 담을 리스트 객체 생성. # Default는 k=3
kfold = KFold(n_splits=5)
classifier = DecisionTreeClassifier(random_state=156)
n_iter = 0
cv_accuracy = []
# kfold.split(features): KFold객체의 split( ) 호출하면 fold 별 학습용, 검증용 테스트의 로우 인덱스를 array로 반환
for train_index, val_index in kfold.split(features):
# 전체 붓꽃 데이터가 모두 150 개이므로
#print(train_index, test_index) #이를 출력해보면, 정말 training data 120개, val data 30개의 index가 출력된다.
X_train, X_val = features[train_index], features[val_index]
y_train, y_val = target[train_index], target[val_index]
#교차 검증시(반복문이 한 번 수행 될 때마다)마다 학습과 검증평가를 반복하여 예측 정확도를 측정할 수 있다.
classifier.fit(X_train, y_train)
pred = classifier.predict(X_val)
n_iter += 1
# 반복 시 마다 정확도 측정
accuracy = np.round(accuracy_score(y_val,pred), 4)
train_size = X_train.shape[0]
val_size = X_val.shape[0]
print('{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}'
.format(n_iter, accuracy, train_size, val_size))
print('{0} 검증 세트 인덱스:{1}'.format(n_iter,val_index))
cv_accuracy.append(accuracy)
# 개별 iteration별 정확도를 합하여 "평균" 정확도 계산
print('평균 검증 정확도:', np.mean(cv_accuracy))
② Stratified K 폴드 교차 검증
※ imbalanced한 label 데이터 집합을 위한 K 폴드 방식
imbalanced한 label 데이터 집합은 특정 label값이 상대적으로 너무 많거나 너무 적어서 값의 분포가 치우쳐 불균형한 것을 말한다. 이런 경우 랜덤하게 training/test data를 나누더라도 (분류 문제라고 치면, ) label이 거의 모두 다 0일 수도 있고, 거의 모두 1일 수도 있고,.. 비율을 제대로 맞출 수 없을 것이다.
Stratified K 폴드 교차 검증 방법은 전체 데이터의 label분포를 먼저 고려한 뒤, 이 분포와 동일하게 training/ validation data 세트로 분배해준다.
Stratified K 폴드 교차 검증 코드)
# 붓꽃 예측을 위해서 필요한 sklearn 모듈 불러오기
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier #DecisionTree모델을 사용할 것임.
#from sklearn.model_selection import train_test_split
#from sklearn.model_selection import KFold
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import accuracy_score
#그 외
import pandas as pd
import numpy as np
iris_data = load_iris()
iris = load_iris()
features = iris.data
target = iris.target
skfold = StratifiedKFold(n_splits=5)
classifier = DecisionTreeClassifier(random_state=156)
n_iter = 0
cv_accuracy = []
# StratifiedKFold의 split( ) 호출시 반드시 label 데이터도 추가 입력 필요
# 왜냐면 label 데이터의 분포를 보고, 이를 참고해서 나누기 때문
for train_index, val_index in skfold.split(features,target):
# 전체 붓꽃 데이터가 모두 150 개이므로
#print(train_index, test_index) #이를 출력해보면, 정말 training data 120개, val data 30개의 index가 출력된다.
X_train, X_val = features[train_index], features[val_index]
y_train, y_val = target[train_index], target[val_index]
#교차 검증시(반복문이 한 번 수행 될 때마다)마다 학습과 검증평가를 반복하여 예측 정확도를 측정할 수 있다.
classifier.fit(X_train, y_train)
pred = classifier.predict(X_val)
n_iter += 1
# 반복 시 마다 정확도 측정
accuracy = np.round(accuracy_score(y_val,pred), 4)
train_size = X_train.shape[0]
val_size = X_val.shape[0]
print('\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}'
.format(n_iter, accuracy, train_size, val_size))
print('#{0} 검증 세트 인덱스:{1}'.format(n_iter,val_index))
cv_accuracy.append(accuracy)
# 개별 iteration별 정확도를 합하여 "평균" 정확도 계산
print('\n## 평균 검증 정확도:', np.mean(cv_accuracy))
※ 일반적으로 분류(Classificaation)문제는 교차 검증시 Stratified K 폴드로 데이터세트를 분할하여 학습과 검증을 진행해야한다. 그러나 회귀(Regression)의 경우 Stratified K 폴드가 지원되지 않는다. 왜냐하면 회귀의 label들은 이산값 형태가 아니라 연속된 숫자이기 때문에 결정값별로 분포를 정하는 의미가 없기 때문이다.
2. 교차 검증을 위한 Sklearn API
① cross_val_score
scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html
위의 (Stratified) K 폴드 교차 검증 코드를 보면 아래의 3단계로 이루어진다. 이 과정을 한꺼번에 수행해주는 API가 cross_val_score이다. 즉, 이 API 내에서 분할,학습, 예측, 평가를 다 수행해준다.
1. 폴드 세트를 설정하고
2. for 루프에서 반복적으로 학습 및 테스트 데이터의 인덱스를 추출한 뒤
3. 반복적으로 학습과 예측을 수행하고 예측 성능을 반환
sklearn.model_selection.cross_val_score(estimator, X, y=None, *, groups=None, scoring=None,
cv=None, n_jobs=None, verbose=0, fit_params=None, pre_dispatch='2*n_jobs', error_score=nan)
주요 Parameters)
estimator: 알고리즘 클래스 ex) Classifier 또는 Regressor가 될 수 있다. Classifier이면 Stratified K 폴드 방식, Regressor이면 K 폴드 방식,으로 분할한다.
X: feature dataet
y: label dataset
scoring: 예측 성능 평가 지표
cv: 교차 검증 폴드 수
Return 값)
scoring 파라미터로 지정된 성능 지표 측정값의 배열 형태
그래서 사용시에는 이 Return 된 배열 값을 평균해서 사용한다.
cross_val_score 코드)
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score , cross_validate
from sklearn.datasets import load_iris
import numpy as np
iris_data = load_iris()
dt_clf = DecisionTreeClassifier(random_state=156)
data = iris_data.data
label = iris_data.target
# 성능 지표는 정확도(accuracy) , 교차 검증 세트는 3개
scores = cross_val_score(dt_clf , data , label , scoring='accuracy',cv=3)
print('교차 검증별 정확도:',np.round(scores, 4))
print('평균 검증 정확도:', np.round(np.mean(scores), 4))
② GridSearchCV
scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html
하이퍼 파라미터를 저정하면서 알고리즘의 예측 성능을 개선할 수 있다. 그러나 매번 하나씩 값을 변경해가면서 그때마다 결과를 보는 것을 반복하기에는 너무 번거롭다. 알고리즘에 사용되는 하이퍼 파라미터를 순차적으로 입ㄹ력하면서 편리하게 최적의 파라미터를 도출해 낼 수 있게 해주는 API가 GridSearchCV이다.
class sklearn.model_selection.GridSearchCV(estimator, param_grid, *, scoring=None,
n_jobs=None, iid='deprecated', refit=True, cv=None, verbose=0,
pre_dispatch='2*n_jobs', error_score=nan, return_train_score=False)
주요 Parameters)
estimator: 알고리즘 클래스 ex) Classifier 또는 Regressor 또는 pipeline가 될 수 있다.
param_grid: key+리스트 값을 가지는 딕셔너리가 주어진다. estimator의 튜닝을 위해 파라미터명과 사용될 여러 파라미터 값을 지정
scoring: 예측 성능 평가 지표
cv: 교차 검증 폴드 수
refit: 디폴트가 True이며 True로 생성시 가장 최적의 하이퍼 파라미터를 찾은 뒤 입력된 estimator객첼를 해당 하이퍼 파라미터로 재학습 시킨다.
Return 값)
scoring 파라미터로 지정된 성능 지표 측정값의 배열 형태
그래서 사용시에는 이 Return 된 배열 값을 평균해서 사용한다.
GridSearchCV 코드)
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd
#데이터를 train_test_split을 이용해서 로딩하고 학습 데이터와 테스트 데이터 분리
iris_data = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris_data.data, iris_data.target,
test_size=0.2, random_state=121)
#classifier는 DecisionTree 사용
dtree = DecisionTreeClassifier()
#실험하고 싶은 DicisionTree의여러 하이퍼 파라미터를 딕셔너리 형태로 설정
parameters = {'max_depth': [1, 2, 3], 'min_samples_split': [2, 3]}
# param_grid의 하라퍼 파라미터를 3개의 trian, test set fold로 나누어 테스트를 수행
## refit = True이면 가장 좋은 파라미터 설정으로 재학습시킴
grid_dtree = GridSearchCV(dtree, param_grid=parameters, cv=3, refit=True)
#.fit은 train data를 cv에 폴딩 세트로 분할해서 param_grid 하이퍼 파라미터들을 순찹적으로 변경하면서 학습/ㅍ펴가를 수행하고,
grid_dtree.fit(X_train, y_train)
# 그 결과를 cv_resuls_ 속성에 기록한다.
# cv_results_는 딕셔너리 형태로 key 값과 리스트 형태의 value값을 가진다.
#print(grid_dtree.cv_results_) 그냥 이렇게 보면 헷갈리니까 DataFrame형태로 바꿔서 봐본다.
scores_df = pd.DataFrame(grid_dtree.cv_results_)
# 결과 보기
# scores_df.head()
scores_df[['params', 'mean_test_score', 'rank_test_score',
'split0_test_score', 'split1_test_score', 'split2_test_score']]
# .fit의 최고 성능을 나타낸 하이퍼 파라미터의 값과 그떼의 평가 결과 값이 각각 best_params, best_score_ 속성에 길록된다.
print('GridSearchCV 최적 파라미터:', grid_dtree.best_params_)
print('GridSearchCV 최고 정확도: {0:.4f}'.format(grid_dtree.best_score_))
# refit=True로 설정된 GridSearchCV 객체가 fit()을 수행 시 학습이 완료된 Estimator를 내포하고 있으므로 predict()를 통해 예측도 가능.
pred = grid_dtree.predict(X_test)
print('테스트 데이터 세트 정확도: {0:.4f}'.format(accuracy_score(y_test,pred)))
지금까지 파이썬 머신러닝 완벽 가이드 수업을 바탕으로
Sklearn에 대한 소개와
Sklearn의 Model Selection 모듈에 있는 train/test data set 분리 및 Cross Validation 에 대해서 정리해 보았다.
다음 포스트에서는 sklearn을 이용한 데이터 전처리 방법들에 대해서 정리해 볼 것이다.
최종 모델 결정 방법
Reference
파이썬 머신러닝 완벽 가이드 - 권철민 저
'Data Science > Machine Learning' 카테고리의 다른 글
Evaluation2. 회귀의 성능 평가 지표(MAE, MSE, RMSE, R제곱) (0) | 2020.09.28 |
---|---|
Evaluation1 - 분류 모델 성능 지표 (Accuracy, Confusion Matrix, Precision, Recall, F1 score, ROC AUC ) (0) | 2020.09.28 |
2. numpy - ndarray 인덱싱 & 슬라이싱 이해 (0) | 2020.09.15 |
1. numpy - numpy 모듈 & ndarray 이해 (0) | 2020.09.14 |
Machine Learning 마인드맵 (0) | 2020.04.30 |