본문 바로가기
Study/Machine learning

[Machine learning] 스태킹 알고리즘 (Stacking algorithm) - 앙상블, 배깅, 부스팅 정리 200728

by 후이 (hui) 2020. 7. 28.
728x90
반응형

 

 

 

index

1. 스태킹 알고리즘의 개념 

2. 코드 예제 

3. 앙상블 - 스태킹, 배깅, 부스팅

4. 스태킹의 장단점

5. 단점을 보완하는 CV세트기반 스태킹 

6. 코드예제 

 

1. 스태킹 알고리즘 

여러 모델들을 활용해 각각의 예측 결과를 도출한 뒤 그 예측 결과를 결합해 최종 예측 결과를 만들어내는 것

 

따라서 스태킹 알고리즘에는 총 2가지 단계가 있는데 

단계 1. n 개의 모델로 학습 데이터로 학습 모델 생성

단계 2. n 개의 모델에서 학습을 마친 뒤 예측한 값들을 합쳐서 최종 예측

 

 

단계 1 과정에서 해당되는게 아래 그림의 Regression models 이고

단계 2 과정에 해당 되는게 Meta-regressor이다.

아래의 사진은 회귀 예측을 기준으로 그림을 도식화 했는데 만약 분류 문제라면 

Regression 을 Classification 워딩으로 바꿔서 이해 여기서 중요한 건 2번 학습을 거치는 개괄 구조다.

 

 

 

따라서 우리는 모델을 설계할 때,

단계1 에 사용할 여러가지 모델들과 /

단계1 의 결과를 취합한 뒤 결과를 도출할 단계 2의 마지막 모델을 뭘로 할지 정해야 한다. 

 

 

코드를 통해 살펴보면

 

 

2. 코드 (출처 파이썬 머신러닝 완벽 가이드 p280)

단계 1. n 개의 모델 각각 학습데이터로 학습 진행

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_training , X_testing , y_training , y_testing = train_test_split(X_data , y_label , test_size=0.2 , random_state=0)

# 개별 ML 모델을 위한 Classifier 생성.
knn_clf  = KNeighborsClassifier(n_neighbors=4) #K최근접이웃
rf_clf = RandomForestClassifier(n_estimators=100, random_state=0)#랜덤포레스트
dt_clf = DecisionTreeClassifier() #결정트리
ada_clf = AdaBoostClassifier(n_estimators=100) #아다부스트

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

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

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

사용된 학습 데이터는 위스콘신 유방암 분류 데이터 이며, 악성/양성 두가지로 분류해야하는 분류 데이터셋이다.

 

단계 1에서는 해당 데이터를 분류하는 모델로 4가지를 선택했다. 

K 최근접이웃(KNeighborsClassifier), 랜덤포레스트(RandomForestClassifie),

결정트리(DecisionTreeClassifier), 아다부스트(AdaBoostClassifier)

 

그리고 각 모델들의 학습 시킨뒤 (fit) 시험 데이터로 (X_testing) 모델을 분류한 결과의 정확도를 확인했다. 

 

 

 

단계 2. n 개의 모델에서 학습을 마친 뒤 예측한 값들을 합쳐서 최종 예측

 

이제 전 단계에서 시험데이터를 통해 예측된 결과를 합쳐 최종 분류기에 넣는 과정이다. 

# 시험데이터로 예측한 4가지 모델의 결과를 합침
pred = np.array([knn_pred, rf_pred, dt_pred, ada_pred])
print(pred.shape)

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

# 최종 분류기 모델 생성
lr_final = LogisticRegression(C=10)

# 최종 분류기 학습 및 예측
lr_final.fit(pred, y_testing)
final = lr_final.predict(pred)

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

 

사용된 최종 분류기 모델은 로지스틱 회귀모델이다. (잊지말자 로지스틱 회귀모델은 회귀모델로 이름을 맨들었으나, 분류 모델인것을...)

해당 모델의 인풋으로 들어가는 것은 

단계 1에서 생성된 각 모델의 예측 결과가 통합된 어레이 형태의 값이다. 해당 어레이를 출력해보면 값은 아래와 같다. 

 

Q. 그렇다면 질문, 4가지 모델에서 학습 할때 사용된 데이터 피쳐들, 학습 파라미터들은 단계2의 로지스틱 모델에서 활용되지 않는 것인가?

그렇다. 단순히 모델의 결과값이 새로운 인풋이 되는 것임.

 

 

3. 앙상블 - 스태킹, 배깅, 부스팅

 

앙상블 기법은 머신러닝 모델의 성능을 향상할 때 많이 쓰이는 기법으로, 하나의 모델이 아닌 여러 학습 모델을 활용해 학습을 진행시키는 것이다. 앙상블 기법에는 부스팅(boosting), 배깅(bagging) 그리고 스태킹이 있다. 스태킹의 친구들인 배깅과 부스팅을 살펴보자면.

 

Bagging 배깅
출처 : Data Mining: Accuracy and Error Measures for Classification and Prediction

Random sampling 통해 한 데이터를 랜덤샘플링 한 뒤, 동일한 여러개의 모델로 학습을 진행하고, 각 모델의 예측결과를 취합하여 하나의 결과를 내는 방법.  

=> 각각의 모델들은 랜덤 샘플링한 데이터로 학습, 종류는 같은 모델임
   (의사결정트리1/ 의사결정트리2 ... 의사결정트리N)
      ==>이걸 랜덤 포레스트라고 부른다.

Boosting 부스팅

 

 

Bagging 의변형으로
이전모델이 예측하지 못한 데이터에 대해 가중치를 두어서 다음 모델이 더 잘 학습 할 수 있도록 하는 방법
bias 를 감소시키는 방법

=> 오답에 가중치를 부여해서 재학습 하는 방식 (오답노트개념)

ex. XGboost, Gradient Boost, AdaBoost

 

+) 배깅은 마지막에 각 모델들의 결과값을 어떻게 취합하나? 보팅으로!

즉, 배깅은 그림에서 보는 것과 같이 데이터를 부분 부분 랜덤 샘플링하여 각 데이터들을 학습시키는 여러 개의 분류기를 만들고,

여러개의 분류기에서 나온 결과를 voting(투표) 하여 테스트 데이터의 성능을 평가한다. 

가령 개고양이를 분류하는 문제를 배깅으로 풀고 배깅으로 생성한 모델이 3개인데 특정 사진을 입력했을 때

모델1 : 개,  모델2: 고양이,  모델 3: 고양이 라고 각각 예측했을 경우 보팅에 따라 고양이로 결론내려진다.

 

** 여기서 주의!

일반적인 voting 은 동일한 데이터셋 (100%)를 활용해다른 모델을 학습하고 각 모델의 결과를 투표를 통해서 결정하는데 

배깅의 보팅은 랜덤 샘플링한 일부의 데이터셋을 활용해 다 같은 모델을 학습하고 각 모델의 결과를 투표를 통해서 결정 

 

 

부스팅/ 배깅 은 편향 분산 모델의 일반화 과적합과 같은 개념과도 다 연결되어있는 중요한 컨셉이라서 이부분은 나중에 한번더 

깊게 다뤄보도록 하겠고.. 다시 스태킹으로 돌아와서.....

 

4. 스태깅의 장점 단점

 

장점 : 단일 모델로 했을때 보다 성능이 확연히 향상된다. 

단점 : 과적합 (overfitting)

 

스태킹은 여러 모델들의 학습 결과로 메타 학습을 거치기 때문에 학습 데이터에 한에서 우수한 성능을 보일수 밖에 없다. 따라서 주로 캐글 경진대회에서 마지막 성능 올리기의 치트키로 쓰이는 기법들 중 하나다. 

 

하지만 학습데이터와 도메인이 다르거나 분산이 다른 데이터가 들어오게 된다면

모델의 예측/분류 성능은 현저히 떨어지게 된다. 

왜냐면 스태킹은 두 단계 (1. n개의 모델생성 2. n개의 모델 결과로 메타 학습) 을 거치며,

학습데이터에 과적합 되었기 때문이다.

따라서 이를 보완하기 위해 2번째 단계에서 교차 검증 과정을 추가하는 방법이 있는데 이게 바로 CV 세트기반 스태킹이다. 

 

 

여기서 교차 검증은 이 포스팅을 참고~!

https://huidea.tistory.com/30?category=879541

 

[Machine learning] 쉽게 설명하는 Cross Validation 교차검증

index 교차검증이란? 교차검증을 사용하는 이유 코드 및 결과  추가 질문들 (Stratified K-fold 교차검증) 1. 교차 검증 (cross validation) : 모델의 학습 과정에서 학습 / 검증데이터를 나눌때 단순히 1번 나

huidea.tistory.com

 

5. CV 세트기반 스태킹

이는 앞서 말한 스태킹 학습 과정에서 교차 검증(Cross validation)을 추가한 것인데, 하나씩 살펴보자면 

설명을 위해 스태킹에서 쓰이는 모델은 앞에서 본 네가지의 모델이라 하고 임의로 1,2,3,4 모델로 칭하겠음 

 

 

단계 1. 4개의 모델 각각 학습 데이터로 학습을 진행한 후 시험데이터의 예측 결과 4개를 생성.

 

*** 이때 각각의 모델에 교차 검증 적용함 

가령 1번 모델에서 교차검증 3번을 적용하면 전체 데이터 셋은 3개의 폴드로 나눠짐 

각 폴드별 예측한 결과 값 (result_a), 그리고 3개의 폴드 결과값의 평균 값 (result_b)  총 두가지 결과 값이 한 모델에서 생성됨 

이때 result_a 가 2단계 메타 모델의 학습데이터로, result_b가 2단계 메타 모델의 테스트 데이터로 활용

 

총 4가지 모델은 3개의 폴드로 교차 검증 학습을 거쳤기에 

result_a의 개수는 한 모델별 3개, 총 (3*4) 12개며 이것이 메타모델의 학습 데이터로 활용된다 

result_b의 개수는 한 모델별 1개, 총 (1*4) 4개며 이것이 메타모델의 시험 데이터가 된다. 

 

단계 2. 메타 모델은 result_a로 학습을 마친 뒤 result_b로 성능을 평가받는다. 

 

출처 : https://blog.naver.com/PostView.nhn?blogId=ckdgus1433&logNo=221588139765

여기서 노란색이 위 설명의 result_a (각 모델의 각 폴드별 예측값)

주황색?갈색 이 위 설명의 result_b (각 폴드별 예측값의 평균 값. 즉, 한 모델의 예측값) 이다. 

 

+) CV 세트기반 스태킹 코드 (참고용) 

출처 : 파이썬 머신러닝 완벽가이드 

 

from sklearn.model_selection import KFold
from sklearn.metrics import mean_absolute_error

# 개별 기반 모델에서 최종 메타 모델이 사용할 학습 및 테스트용 데이터를 생성하기 위한 함수. 
def get_stacking_base_datasets(model, X_train_n, y_train_n, X_test_n, n_folds ):
    # 지정된 n_folds값으로 KFold 생성.
    kf = KFold(n_splits=n_folds, shuffle=False, random_state=0)
    #추후에 메타 모델이 사용할 학습 데이터 반환을 위한 넘파이 배열 초기화 
    train_fold_pred = np.zeros((X_train_n.shape[0] ,1 ))
    test_pred = np.zeros((X_test_n.shape[0],n_folds))
    print(model.__class__.__name__ , ' model 시작 ')
    
    for folder_counter , (train_index, valid_index) in enumerate(kf.split(X_train_n)):
        #입력된 학습 데이터에서 기반 모델이 학습/예측할 폴드 데이터 셋 추출 
        print('\t 폴드 세트: ',folder_counter,' 시작 ')
        X_tr = X_train_n[train_index] 
        y_tr = y_train_n[train_index] 
        X_te = X_train_n[valid_index]  
        
        #폴드 세트 내부에서 다시 만들어진 학습 데이터로 기반 모델의 학습 수행.
        model.fit(X_tr , y_tr)       
        #폴드 세트 내부에서 다시 만들어진 검증 데이터로 기반 모델 예측 후 데이터 저장.
        train_fold_pred[valid_index, :] = model.predict(X_te).reshape(-1,1)
        #입력된 원본 테스트 데이터를 폴드 세트내 학습된 기반 모델에서 예측 후 데이터 저장. 
        test_pred[:, folder_counter] = model.predict(X_test_n)
            
    # 폴드 세트 내에서 원본 테스트 데이터를 예측한 데이터를 평균하여 테스트 데이터로 생성 
    test_pred_mean = np.mean(test_pred, axis=1).reshape(-1,1)    
    
    #train_fold_pred는 최종 메타 모델이 사용하는 학습 데이터, test_pred_mean은 테스트 데이터
    return train_fold_pred , test_pred_mean
# CV스태킹 알고리즘 각 모델에 적용
knn_train, knn_test = get_stacking_base_datasets(knn_clf, X_train, y_train, X_test, 7)
rf_train, rf_test = get_stacking_base_datasets(rf_clf, X_train, y_train, X_test, 7)
dt_train, dt_test = get_stacking_base_datasets(dt_clf, X_train, y_train, X_test,  7)    
ada_train, ada_test = get_stacking_base_datasets(ada_clf, X_train, y_train, X_test, 7)

# CV스태킹 알고리즘 결과로 메타 모델 학습/시험에 필요한 result_a result_b 만들기 
Stack_final_X_train = np.concatenate((knn_train, rf_train, dt_train, ada_train), axis=1)
Stack_final_X_test = np.concatenate((knn_test, rf_test, dt_test, ada_test), axis=1)

# 메타 모델 학습
lr_final.fit(Stack_final_X_train, y_train)
stack_final = lr_final.predict(Stack_final_X_test)

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

해당 코드에서는 7폴드를 사용하였다. 

 

 

결론 

앙상블은 결국 여러개의 모델들을 쌓고 이어붙이면서 주어진 과업의 성능을 최대한 높이는 방식들이다. 

오늘 스태킹을 살펴보면서 부스팅 배깅을 언급했는데, 이에 대해 더 깊게 분석하는 포스팅을 조만간 올려야겠다

이 개념은 학습 알고리즘에서 중요한 편향/분산과 밀접히 연관되어 있기 때문에! 

 

 

 

 

그럼 20000

 

 

사진 및 자료 출처들 

https://www.researchgate.net/figure/The-bagging-approach-Several-classifier-are-trained-on-bootstrap-samples-of-the-training_fig4_322179244

https://en.wikipedia.org/wiki/Boosting_(machine_learning)

파이썬 머신러닝 완벽 가이드 - 권철민

728x90
반응형

댓글