붓꽃 품종 예측 , 사이킷런 , Model Selection , 데이터 전처리
붓꽃 품종 예측.
1. 붓꽃 데이터를 불러온다.
2. 데이터와 타겟값을 나눈다.
3. 데이터 세트를 분리 한다.
4. 학습한다.(결정트리 사용)
5. 예측한다.
6.예측 정확도를 확인한다.
import pandas as pd
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
iris = load_iris()
iris_data = iris.data
iris_label = iris.target
X_train,X_test,y_train,y_test = train_test_split(iris_data , iris_label,test_size=0.3,random_state=777)
dt_clf = DecisionTreeClassifier(random_state=777)
dt_clf.fit(X_train,y_train)
pred = dt_clf.predict(X_test)
print("예측 정확도 :{:.4f}".format(accuracy_score(y_test,pred)))
사이킷런은 머신러닝 모델 학습을 위해서 fit() , 학습된 모델의 예측을 위해 predict() 메서드를 제공.
사이킷런은 매우 많은 유형의 Classifier(분류) & Regression(회귀) 클래스를 제공하는데 이들을 Estimator 클래스라 합니다.
예제 데이터 sklearn.datasets : 사이킷런에 내장되어 예제로 제공하는 데이터 세트
피처처리 sklearn.preprocessing : 데이터 전처리에 필요한 다양한 가공 기능 제공(정규화,스케일링 등)
sklearn.feature_selection : 알고리즘에 큰 영향을 미치는 피처를 우선순위대로 셀렉션 작업 수행.
sklearn.feature_extraction : 텍스트 데이터나 이미지 데이터의 벡터화된 피러를 추출하는데 사용됨.
피처 처리 & 차원 축소 sklearn.decomposition :PCA , NMF , SVD 등을 통해 차원 축소.
데이터 분리, 검증 & 파라미터 튜닝 sklearn.model_selection : 교차검증을 위한 학습용 / 테스트용 분리, GridSearch API제공.
평가 sklearn.metrics : 분류,회귀,클러스터링,페어와이즈에 대한 다양한 성능 측정 방법 제공
ML 알고리즘 : sklearn.ensemble , sklearn.linear_model , sklearn.naive_bayes , sklearn.neighbors 등
유틸리티 sklearn.pipeline : 피처 처리 등의 변환과 ML 알고리즘 학습,예측 등을 함계 묶어서 실행할 수 있는 유틸리티 제공.
교차검증
> 고정된 학습 데이터와 테스트 데이터로 평가하다 보면 테스트 데이터에만 최적의 성능을 발휘할 수 있도록 편향되게 모델을 유도하는 경향이 생긴다. >> 오버피팅
K 폴드 교차 검증
> 가장 보편적인 교차 검증 기법이다. K개의 데이터 폴드 세트를 만들어서 K번 만큼 각 폴트 세트에 학습과 검증 평가를 반복적으로 수행하는 방법 .
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
import numpy as np
iris = load_iris()
features = iris.data
label = iris.target
dt_clf = DecisionTreeClassifier(random_state=777)
kfold = KFold(n_splits=5) # 5개의 폴드 세트로 분리하는 KFold 객체.
cv_accuracy = [] # 폴드 세트별 정확도를 담을 리스트 객체 생성.
print("붓꽃 데이터 세트 크기 :",features.shape[0])
n_iter =0
#KFold 의 split()은 폴드 별 학습용 / 검증용 테스트의 row index를 array로 반환
for train_idx , test_idx in kfold.split(features):
#kfold.split()으로 반환된 인덱스를 이용해 학습용 / 검증용 테스트 데이터 추출.
X_train , X_test = features[train_idx] , features[test_idx]
y_train , y_test = label[train_idx] , label[test_idx]
#학습 / 예측
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)
cv_accuracy.append(accuracy)
print("{} 번째 예측 정확도 : {} ".format(n_iter , accuracy))
print("\n평균 정확도 : ",np.mean(cv_accuracy))
붓꽃 데이터 세트 크기 : 150
1 번째 예측 정확도 : 1.0
2 번째 예측 정확도 : 1.0
3 번째 예측 정확도 : 0.9
4 번째 예측 정확도 : 0.9333
5 번째 예측 정확도 : 0.8
평균 정확도 : 0.92666
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()
0 50
1 50
2 50
Name: label, dtype: int64
이슈가 발생하는 현상을 도출하기 위해 3개의 폴드 세트를 KFold로 생성하고 각 교차 검증 시마다 생성되는 학습/검증 레이블 데이터 값의 분포도를 확인
kfold = KFold(n_splits=3)
n_iter =0
for train_idx , test_idx in kfold.split(iris_df):
n_iter += 1
label_train = iris_df['label'].iloc[train_idx]
label_test = iris_df['label'].iloc[test_idx]
print(" 교차 검증 : {}".format(n_iter))
print("학습 레이블 데이터 분포:\n",label_train.value_counts())
print("검증 레이블 데이터 분포:\n",label_test.value_counts())
교차 검증 : 1
학습 레이블 데이터 분포:
1 50
2 50
Name: label, dtype: int64
검증 레이블 데이터 분포:
0 50
Name: label, dtype: int64
교차 검증 : 2
학습 레이블 데이터 분포:
0 50
2 50
Name: label, dtype: int64
검증 레이블 데이터 분포:
1 50
Name: label, dtype: int64
교차 검증 : 3
학습 레이블 데이터 분포:
0 50
1 50
Name: label, dtype: int64
검증 레이블 데이터 분포:
2 50
Name: label, dtype: int64
위와 같이 학습 레이블과 검증 레이블이 아예 겹치지 않는 현상이 생긴다. 이렇게 되면 정확도가 떨어질 수 있다.
StratifiedKFold는 이렇게 KFold로 분할된 레이블 데이터 세트가 전체 레이블 값의 분포도를 반영하지 못하는 문제를 해결한다.
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=3)
n_iter =0
for train_idx , test_idx in skf.split(iris_df , iris_df['label']):
n_iter += 1
label_train = iris_df['label'].iloc[train_idx]
label_test = iris_df['label'].iloc[test_idx]
print("교차 검증 : {}".format(n_iter))
print("학습 레이블 데이터 분포 :\n",label_train.value_counts())
print("검증 레이블 데이터 분포 : \n",label_test.value_counts())
교차 검증 : 1
학습 레이블 데이터 분포 :
2 34
0 33
1 33
Name: label, dtype: int64
검증 레이블 데이터 분포 :
0 17
1 17
2 16
Name: label, dtype: int64
교차 검증 : 2
학습 레이블 데이터 분포 :
1 34
0 33
2 33
Name: label, dtype: int64
검증 레이블 데이터 분포 :
0 17
2 17
1 16
Name: label, dtype: int64
교차 검증 : 3
학습 레이블 데이터 분포 :
0 34
1 33
2 33
Name: label, dtype: int64
검증 레이블 데이터 분포 :
1 17
2 17
0 16
Name: label, dtype: int64
이로써 학습데이터와 검증 데이터의 불균등성이 해소됨을 알 수 있다.
전 과 같이 균형성 있는 데이터를 바탕으로 학습과 예측을 하면 ,
dt_clf = DecisionTreeClassifier(random_state=777)
skfold = StratifiedKFold(n_splits=3)
n_iter =0
cv_accuracy = []
for train_idx , test_idx in skfold.split(features, label):
#kfold.split()으로 반환된 인덱스를 이용해 학습용 / 검증용 테스트 데이터 추출.
X_train , X_test = features[train_idx] , features[test_idx]
y_train , y_test = label[train_idx] , label[test_idx]
#학습 / 예측
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)
cv_accuracy.append(accuracy)
print("{} 번째 예측 정확도 : {} ".format(n_iter , accuracy))
print("\n평균 정확도 : ",np.mean(cv_accuracy))
1 번째 예측 정확도 : 0.98
2 번째 예측 정확도 : 0.94
3 번째 예측 정확도 : 0.98
평균 정확도 : 0.9666666666666667
평균 정확도가 증가한 것을 알 수 있다.
일반적으로 분류(Classification)에서의 교차 검증은 K폴드가 아니라 Stratified K 폴드로 분할돼야 합니다. 회귀(Regression)에서는 Stratifed K 폴드가 지원되지 않는다. 회귀의 결정값은 연속된 숫자기 때문에 결정값별로 분포를 정하는 의미가 없기 때문.
이러한 교차 검증을 보다 간편하게 제공해주는 사이킷런의 API를 살펴보자.
cross_val_score()는 폴드 세트를 설정하고 , for 루프에서 반복으로 학습 및 테스트 데이터의 인덱스를 추출한뒤 , 반복적으로 학습과 예측을 수행하고 예측 성능을 반환하는 과정을 한꺼번에 수행해주는 API입니다.
주요 파라미터는 estimator(알고리즘) ,X(피처 데이터세트) , y(레이블 데이터세트) ,scoring(예측 성능 평가 지표) ,cv(교차 검증 폴드 수)가 있습니다.
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score , cross_validate
from sklearn.datasets import load_iris
iris_data = load_iris()
dt_clf = DecisionTreeClassifier(random_state=777)
data = iris.data
label = iris.target
#성능 지표는 정확도 , 교차 검증세트는 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))
교차 검증별 정확도 : [0.98 0.94 0.98]
평균 검증 정확도: 0.9667
GridSearchCV
> 하이퍼 파라미터 튜닝 방식.
주요 파라미터
params 칼럼에는 수행할때마다 적용된 개별 하이퍼 파라미터값.
rank_test_score는 하이퍼 파라미터별로 성능이 좋은 socre 순위를 나타냄.
mean_test_score는 개별 하이퍼 파라미터별로 CV의 폴딩 테스트 세트에 대해 총 수행한 평가 평균값.
GridSearchCV객체의 fit()를 수행하면 최고 성능을 나타낸 하이퍼 파라미터의 값과 그때의 평가 결과값이 각각
best_params_ , best_score_속성에 기록됩니다.
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
import pandas as pd
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)
dtree = DecisionTreeClassifier()
#파라미터를 딕셔너리 형태
parameters = {'max_depth':[1, 2, 3], 'min_samples_split':[2,3]}
grid_dtree = GridSearchCV(dtree, param_grid=parameters, cv=3, refit=True, return_train_score=True)
# 붓꽃 Train 데이터로 param_grid의 하이퍼 파라미터들을 순차적으로 학습/평가 .
grid_dtree.fit(X_train, y_train)
# GridSearchCV 결과는 cv_results_ 라는 딕셔너리로 저장됨. 이를 DataFrame으로 변환
scores_df = pd.DataFrame(grid_dtree.cv_results_)
scores_df[['params', 'mean_test_score', 'rank_test_score',
'split0_test_score', 'split1_test_score', 'split2_test_score']]
print("GridSearchCV 최적 파라미터:",grid_dtree.best_params_)
print("GridSearchCV 최고 정확도:{:.4f}".format(grid_dtree.best_score_))
GridSearchCV 최적 파라미터: {'max_depth': 3, 'min_samples_split': 2}
GridSearchCV 최고 정확도:0.9750
피러 스케일링과 정규화
StandardScaler
> 표준화를 쉽게 지원하기 위한 클래스. 개별 피처를 평균 0 분산 1인 값으로 변환해준다.
from sklearn.datasets import load_iris
import pandas as pd
iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data , columns=iris.feature_names)
print("feature들의 평균 값")
print(iris_df.mean())
print("\nfeature들의 분산 값")
print(iris_df.var())
feature들의 평균 값
sepal length (cm) 5.843333
sepal width (cm) 3.057333
petal length (cm) 3.758000
petal width (cm) 1.199333
dtype: float64
feature들의 분산 값
sepal length (cm) 0.685694
sepal width (cm) 0.189979
petal length (cm) 3.116278
petal width (cm) 0.581006
dtype: float64
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
iris_df_scaled = pd.DataFrame(data=iris_scaled , columns=iris.feature_names)
print("feature들의 평균 값")
print(iris_df_scaled.mean())
print("\nfeature들의 분산 값")
print(iris_df_scaled.var())
feature들의 평균 값
sepal length (cm) -1.690315e-15
sepal width (cm) -1.842970e-15
petal length (cm) -1.698641e-15
petal width (cm) -1.409243e-15
dtype: float64
feature들의 분산 값
sepal length (cm) 1.006711
sepal width (cm) 1.006711
petal length (cm) 1.006711
petal width (cm) 1.006711
dtype: float64
MinMaxScaler
> 데이터값을 0과 1사이의 범위 값으로 변환