데이터 분석/왕초보를 위한 머신러닝

[머신러닝 기초] 지도학습 - classification (Ensemble, Random Forest)

ai-creator 2021. 10. 16. 10:13
반응형

목차

1. 앙상블 (ensemble)

2. Bagging

  • 2-1) Random Foreset

3. Boosting

4. Staking

 

1. 앙상블(ensemble)

- 여러개의 분류기(classifier)를 생성하고, 그 예측을 결합함으로써 더 정확한 최종 예측을 도출하는 기법

- 어려운 문제를 풀기위해 여러명의 전문가로 구성해 다양한 의견을 수렴하고 결정하는 방법과 유사

1-1) 앙상블 유형

  • 보팅 (Voting) : 서로 다른 알고리즘을 가진 분류기를 결합
  • 배깅 (Bagging, Bootstrap AGGregatING) : 모두 같은 유형의 알고리즘을 사용하지만, 데이터 샘플링(sampling with replacement, 복원추출)을 서로 다르게 가져가면서 보팅을 수행, RandomForest
    • 데이터 샘플링 => 부트스트래핑(Bootstrapping) 분할 방식을 사용
  • 부스팅 (Boosting) : 여러개의 분류기가 순차적으로 학습을 수행하되, 앞에서 학습한 분류기가 예측이 틀린 데이터에 대해서는 올바르게 예측할 수 있도록 다음 분류기에게는 가중치(weight)를 부여하면서 학습과 예측을 진행, XGBoost, LightGBM
  • 스태킹 (Stacking) : 여러가지 다른 모델의 예측 결괏값을 다시 학습 데이터로 만들어서 다른 모델(메타모델)로 재학습시켜 결과를 예측하는 방법

등등....

출처 : https://velog.io/@sset2323/04-03.-%EC%95%99%EC%83%81%EB%B8%94-%ED%95%99%EC%8A%B5
Boosting 방식 (출처 : https://kimdingko-world.tistory.com/181)
출처 : https://swalloow.github.io/bagging-boosting/

 

1-2) Voting 방식

Voting방식은 Hard Voting, Soft Voting이 있으며, 일반적으로 Soft Voting이 예측성능이 우수하여 더 많이 사용한다.

출처 : https://velog.io/@sset2323/04-03.-%EC%95%99%EC%83%81%EB%B8%94-%ED%95%99%EC%8A%B5

 

1-3) 부트스래핑

- 복원추출 샘플링

- 데이터가 중복되어 구성될 수도 있고, 데이터가 아에 포함이 안될 수도(OOB, Out of Bag) 있다.

- 이는 데이터가 갖는 분포를 왜곡시켜주는 효과가 있어 학습을 더 정확하게 할 수 있으며, OOB를 사용하여 데이터 검증을 할 수 있다.

 

2. Bagging  (Bagging, Bootstrap AGGregatING)

- 모두 같은 유형의 알고리즘을 사용

- 데이터 샘플링을 Bootstraping 기법을 사용

- 예측결과를 합침 (Aggregation), 합치는 방법은 다양함

Bagging with Decision Tree / Bagging
참고) Aggregation example

2-1) Random Forest

  • Random Forest는

   1) Forest : Decision Tree를 여러개의 분류기로 ensemble

   2) Random : 변수(feature, variable)를 임의(random)선택함

  • Bagging 방식으로 같은 알고리즘으로 여러개의 분류기를 만들어서 보팅으로 최종 결정하는 알고리즘
    • bootstraping 방식으로 데이터 샘플링

  • 여러개의 결정 트리 분류기가 전체 데이터에서 배깅 방식으로 각자의 데이터를 샘플링해 개별적으로 학습을 수행한 뒤 최종적으로 모든 분류기가 소프트보팅을 통해 예측을 결정

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API
Random Forest from sklearn.ensemble import RandomForestClassifier RandomForestClassifier()

주로 사용하는 parameter는 다음과 같다.

** Decision Tree에서 과적합을 개선하기 위한 파라메터도 똑같이 적용됨

파라메터 설명
n_estimators - 결정 트리 개수
- default : 10
** 많이 설정할 수록 좋은 성능을 기대할 수 있지만 계속 증가시킨다고 무조건 향상되는 것은 아님
max_features - sqrt 
max_depth ** Decision Tree와 동일
min_samples_leaf
min_samples_split

> 참고 : 전체 코드 Link (클릭)

코드에서 보면, 

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

rf_clf1 = RandomForestClassifier(n_estimators=300, max_depth=10, min_samples_leaf=8, \
                                 min_samples_split=8, random_state=0)
rf_clf1.fit(X_train , y_train)
pred = rf_clf1.predict(X_test)
print('예측 정확도: {0:.4f}'.format(accuracy_score(y_test , pred)))

GridSearchCV를 사용하는 경우,

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import accuracy_score

params = {
    'n_estimators':[100],
    'max_depth' : [6, 8, 10, 12], 
    'min_samples_leaf' : [8, 12, 18 ],
    'min_samples_split' : [8, 16, 20]
}
# RandomForestClassifier 객체 생성 후 GridSearchCV 수행
rf_clf = RandomForestClassifier(random_state=0, n_jobs=-1)
grid_cv = GridSearchCV(rf_clf , param_grid=params , cv=2, n_jobs=-1 )
grid_cv.fit(X_train , y_train)

print('최적 하이퍼 파라미터:\n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))

Feature importance를 확인 한다면, 

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

ftr_importances_values = rf_clf1.feature_importances_
ftr_importances = pd.Series(ftr_importances_values,index=X_train.columns  )
ftr_top20 = ftr_importances.sort_values(ascending=False)[:20]

plt.figure(figsize=(8,6))
plt.title('Feature importances Top 20')
sns.barplot(x=ftr_top20 , y = ftr_top20.index)
plt.show()

3. Boosting

: 여러개의 분류기가 순차적으로 학습을 수행하되, 앞에서 학습한 분류기가 예측이 틀린사항(ex. 데이터, 잔차)을  다음 분류기에게는 올바르게 예측할 수 있도록 가중치(weight)를 부여하면서 학습과 예측을 진행

 

1) 아다부스트 (AdaBoost) : 오류 데이터에 가중치를 부여하여, 다음 수행에는 더 많이 샘플링 될 수 있도록(부스팅)함

- 즉, 데이터의 샘플링이 달라짐

Boosting 방식 (출처 : https://kimdingko-world.tistory.com/181)

2) 그래디언트 부스트 (Gradient Boost) : Gradient Decent + Boosting 을 의미한다.

- 데이터는 그대로 사용하고, residual(잔차, 실제값-예측값)을 최소화하는 방향성을 가진다.

예) 회귀

잔차로 학습을 진행하므로, overfitting될 가능성이 높음

overfitting을 막기 위해서 (과적합 규제, Regularization)

1) subsampling : 데이터의 일부만 학습

2) early stopping : 설정한 반복횟수를 끝까지 수행하는 것이 아니라, 검증용 데이터셋의 오류가 높아지기 전에 초기 중단을 시키는 방법

등의 방식을 사용함

 

다음부터 배울 GBM, XGBoost, LightGBM는 boosting기법을 사용하여 각 알고리즘들의 단점을 보완하면서 발전하였음.

참고) Decision Tree의 발전 역사

 

3-1) GBM

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API
GBM from sklearn.ensemble import GradientBoostingClassifier
GradientBoostingClassifier()

코드에서 보면, 

from sklearn.ensemble import GradientBoostingClassifier
import time
import warnings
warnings.filterwarnings('ignore')

X_train, X_test, y_train, y_test = get_human_dataset()

# GBM 수행 시간 측정을 위함. 시작 시간 설정.
start_time = time.time()

gb_clf = GradientBoostingClassifier(random_state=0)
gb_clf.fit(X_train , y_train)
gb_pred = gb_clf.predict(X_test)
gb_accuracy = accuracy_score(y_test, gb_pred)

print('GBM 정확도: {0:.4f}'.format(gb_accuracy))
print("GBM 수행 시간: {0:.1f} 초 ".format(time.time() - start_time))

GridSearchCV를 사용하는 경우,

from sklearn.model_selection import GridSearchCV

params = {
    'n_estimators':[100, 500],
    'learning_rate' : [ 0.05, 0.1]
}
grid_cv = GridSearchCV(gb_clf , param_grid=params , cv=2 ,verbose=1)
grid_cv.fit(X_train , y_train)
print('최적 하이퍼 파라미터:\n', grid_cv.best_params_)
print('최고 예측 정확도: {0:.4f}'.format(grid_cv.best_score_))

# GridSearchCV를 이용하여 최적으로 학습된 estimator로 predict 수행. 
gb_pred = grid_cv.best_estimator_.predict(X_test)
gb_accuracy = accuracy_score(y_test, gb_pred)
print('GBM 정확도: {0:.4f}'.format(gb_accuracy))

3-2) XGBoost

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API
XGBoost from xgboost import XGBClassifier
XGBClassifier()

코드에서 보면, 

from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.metrics import precision_score, recall_score
from sklearn.metrics import f1_score, roc_auc_score

def get_clf_eval(y_test, pred=None, pred_proba=None):
    confusion = confusion_matrix( y_test, pred)
    accuracy = accuracy_score(y_test , pred)
    precision = precision_score(y_test , pred)
    recall = recall_score(y_test , pred)
    f1 = f1_score(y_test,pred)
    # ROC-AUC 추가 
    roc_auc = roc_auc_score(y_test, pred_proba)
    print('오차 행렬')
    print(confusion)
    # ROC-AUC print 추가
    print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\
    F1: {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))
######################################################################
# 사이킷런 래퍼 XGBoost 클래스인 XGBClassifier 임포트
from xgboost import XGBClassifier

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
xgb_wrapper.fit(X_train, y_train)
w_preds = xgb_wrapper.predict(X_test)
w_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]

get_clf_eval(y_test , w_preds, w_pred_proba)

 

3-3) LightGBM

Sklearn API

이를 위해 sklearn에서는 API를 지원한다.

목적 import API
LightGBM from lightgbm import LGBMClassifier LGBMClassifier()

코드에서 보면, 

# LightGBM의 파이썬 패키지인 lightgbm에서 LGBMClassifier 임포트
from lightgbm import LGBMClassifier

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.metrics import precision_score, recall_score
from sklearn.metrics import f1_score, roc_auc_score

def get_clf_eval(y_test, pred=None, pred_proba=None):
    confusion = confusion_matrix( y_test, pred)
    accuracy = accuracy_score(y_test , pred)
    precision = precision_score(y_test , pred)
    recall = recall_score(y_test , pred)
    f1 = f1_score(y_test,pred)
    # ROC-AUC 추가 
    roc_auc = roc_auc_score(y_test, pred_proba)
    print('오차 행렬')
    print(confusion)
    # ROC-AUC print 추가
    print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f},\
    F1: {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))

###########################################################################
dataset = load_breast_cancer()
ftr = dataset.data
target = dataset.target

# 전체 데이터 중 80%는 학습용 데이터, 20%는 테스트용 데이터 추출
X_train, X_test, y_train, y_test=train_test_split(ftr, target, test_size=0.2, random_state=156 )

# 앞서 XGBoost와 동일하게 n_estimators는 400 설정. 
lgbm_wrapper = LGBMClassifier(n_estimators=400)

# LightGBM도 XGBoost와 동일하게 조기 중단 수행 가능. 
evals = [(X_test, y_test)]
lgbm_wrapper.fit(X_train, y_train, early_stopping_rounds=100, eval_metric="logloss", 
                 eval_set=evals, verbose=True)
preds = lgbm_wrapper.predict(X_test)
pred_proba = lgbm_wrapper.predict_proba(X_test)[:, 1]
    
 get_clf_eval(y_test, preds, pred_proba)

 

4. Stacking

개별 알고리즘의 예측 결과 데이터 세트를 최종적인 메타 데이터 세트로 만들어 별도의 ML알고리즘으로 최종 핛ㅂ을 수행하는 방식 ("메타모델")

즉, 스태킹 모델은 두종류의 모델이 필요함. 첫번째는 개별적인 "기반 모델"이고, 두번째는 이 개발 기반 모델의 예측 데이터를 학습데이터로 만들어서 학습하는 최종 "메타모델"

출처 : https://subinium.github.io/introduction-to-ensemble-1/

 

import numpy as np

from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

cancer_data = load_breast_cancer()

X_data = cancer_data.data
y_label = cancer_data.target

X_train , X_test , y_train , y_test = train_test_split(X_data , y_label , test_size=0.2 , random_state=0)

# 개별 ML 모델을 위한 Classifier 생성.
knn_clf  = KNeighborsClassifier(n_neighbors=4)
rf_clf = RandomForestClassifier(n_estimators=100, random_state=0)
dt_clf = DecisionTreeClassifier()
ada_clf = AdaBoostClassifier(n_estimators=100)

# 최종 Stacking 모델을 위한 Classifier생성. 
lr_final = LogisticRegression(C=10)

# 개별 모델들을 학습. 
knn_clf.fit(X_train, y_train)
rf_clf.fit(X_train , y_train)
dt_clf.fit(X_train , y_train)
ada_clf.fit(X_train, y_train)

# 학습된 개별 모델들이 각자 반환하는 예측 데이터 셋을 생성하고 개별 모델의 정확도 측정. 
knn_pred = knn_clf.predict(X_test)
rf_pred = rf_clf.predict(X_test)
dt_pred = dt_clf.predict(X_test)
ada_pred = ada_clf.predict(X_test)

print('KNN 정확도: {0:.4f}'.format(accuracy_score(y_test, knn_pred)))
print('랜덤 포레스트 정확도: {0:.4f}'.format(accuracy_score(y_test, rf_pred)))
print('결정 트리 정확도: {0:.4f}'.format(accuracy_score(y_test, dt_pred)))
print('에이다부스트 정확도: {0:.4f} :'.format(accuracy_score(y_test, ada_pred)))

pred = np.array([knn_pred, rf_pred, dt_pred, ada_pred])
print(pred.shape)

# transpose를 이용해 행과 열의 위치 교환. 컬럼 레벨로 각 알고리즘의 예측 결과를 피처로 만듦. 
pred = np.transpose(pred)
print(pred.shape)

lr_final.fit(pred, y_test)
final = lr_final.predict(pred)

print('최종 메타 모델의 예측 정확도: {0:.4f}'.format(accuracy_score(y_test , final)))

ㅁ ensemble 알고리즘별 sklearn API

ensemble 유형 알고리즘 sklearn API hyper-parameter
bagging random foreset from sklearn.ensemble import RandomForestClassifier

RandomForestClassifier()
- n_estimators : 결정트리 개수
- max_features
- max_depth
- min_samples_leaf
boosting GBM (Gradient Boost Machine) from sklearn.ensemble import GradientBoostingClassifier

GradientBoostingClassifier()
- n_estimators
- loss
- learning_rate
- subsample
boosting XGBoost (eXtra Gradient Boost) from xgboost import XGBClassifier

XGBClassifier()
- n_estimators
- learning_rate
- subsample
- reg_lambda
- reg_alpha
boosting LightGBM from lightgbm import LGBMClassifier

LGBMClassifier()
- n_estimators
- learning_rate
- subsample
- reg_lambda
- reg_alpha

ㅁ Reference

- [책] 파이썬 머신러닝 완벽가이드

- [블로그] 파이썬 머신러닝 완벽가이드 정리본 (Link)

- [소스코드 출처] https://github.com/wikibook/pymldg-rev

반응형