[머신러닝 완벽 가이드] 4장_분류 - 스태킹 앙상블

이경민·2023년 1월 11일
0

📌 스태킹 (Stacking)

✅ 개요

  • 개별적인 여러 알고리즘을 서로 결합해 예측 결과를 도출한다는 점에서 배깅(Bagging) 및 부스팅(Boosting)과 공통점을 가진다.

  • 하지만 가장 큰 차이점은 개별 알고리즘으로 예측한 데이터를 기반으로 다시 예측을 수행한다는 것이다.

  • 즉, 개별 알고리즘의 예측 결과 데이터 세트를 최종적인 메타 데이터 세트로 만들어 별도의 ML 알고리즘으로 최종 학습을 수행하고 테스트 데이터를 기반으로 다시 최종 예측을 수행하는 방식이다. (개별 모델의 예측된 데이터 세트를 다시 기반으로 하여 학습하고 예측하는 방식을 메타 모델이라고 한다.)

  • 스태킹 모델은 두 종류의 모델이 필요하다.

    • 개별적인 기반 모델

    • 최종 메타 모델 (개별 기반 모델의 예측 데이터를 학습 데이터로 만들어서 학습)

  • 스태킹 모델의 핵심은 여러 개별 모델의 예측 데이터를 각각 스태킹 형태로 결합해 최종 메타 모델의 학습용 피처 데이터 세트와 테스트용 피처 데이터 세트를 만드는 것이다.

  • 현실 모델에 적용하는 경우는 그렇게 많지 않으며 캐글과 같은 대회에서 조금이라도 성능 수치를 높여야 할 경우 자주 사용된다.

    • 2~3개의 개별 모델만을 결합해서는 쉽게 예측 성능을 향상시킬 수 없으며 많은 개별 모델이 필요하고, 반드시 성능 향상이 되리라는 보장도 없다.

    • 일반적으로 성능이 비슷한 모델을 결합해 좀 더 나은 성능 향상을 도출하기 위해 적용한다.

이미지 출처

✅ 실습 - 기본 스태킹 모델

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)

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

# 최종 모델 생성 (스태킹으로 만들어진 데이터 세트를 학습, 예측)
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)

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

# transpose를 이용해 행과 열의 위치 교환, 각 알고리즘의 예측 결과를 피처로 사용 
pred = np.transpose(pred)
print(pred.shape) # (114, 4)

# 최종 메타 모델 학습, 예측
lr_final.fit(pred, y_test)
final = lr_final.predict(pred)

✅ 실습 - CV 세트 기반의 스태킹

  • 앞 예제에서 메타 모델이 최종 학습할 때 레이블 데이터 세트로 학습 데이터가 아닌 테스트용 레이블 데이터 세트를 기반으로 학습했기에 과적합 문제가 발생할 수 있다.

  • CV 세트 기반의 스태킹 모델은 과적합을 개선하기 위해 최종 메타 모델을 위한 데이터 세트를 만들 때 교차 검증 기반으로 예측된 결과 데이터 세트를 이용한다.

  • 개별 모델들이 각각 교차 검증으로 메타 모델을 위한 학습용 스태킹 데이터 생성과 예측을 위한 테스트용 스태킹 데이터를 생성한 뒤 이를 기반으로 메타 모델이 학습과 예측을 수행한다.

(1) 최종 메타 모델의 학습 데이터 생성

  1. 원본 학습 데이터를 N개의 폴드로 나눈다.
  2. (N-1)개의 폴드는 학습을 위한 데이터 폴드
    나머지 1개의 폴드는 검증을 위한 데이터 폴드
  3. 학습 폴드 데이터로 개별 모델의 학습 수행 후, 검증 폴드 데이터로 예측한 결과를 저장
  4. 이러한 로직을 N번 반복하면서 학습 데이터와 검증 데이터 세트를 변경해가면서 학습 후 예측 결과를 별도로 저장
  5. 이렇게 만들어진 예측 데이터는 메타 모델을 학습시키는 학습 데이터로 사용

(2) 최종 메타 모델의 테스트 데이터 생성

  1. (N-1)개의 학습 폴드 데이터로 학습된 개별 모델은 원본 테스트 데이터를 예측하여 예측값 생성
  2. 이러한 로직을 N번 반복하면서 이 예측값의 평균으로 최종 결괏값을 생성
  3. 이를 메타 모델을 위한 테스트 데이터로 사용

(3) 최종 메타 모델

  • 최종 학습 데이터와 원본 데이터의 레이블 데이터를 합쳐서 메타 모델을 학습

  • 최종 테스트 데이터로 예측을 수행한 뒤, 최종 예측 결과를 원본 테스트 데이터의 레이블 데이터와 비교해 평가

(4) 실습

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)
    #추후에 메타 모델이 사용할 학습 데이터 반환을 위한 넘파이 배열 초기화 
    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


# 개별 모델 학습, 예측 -> 최종 학습/테스트 데이터 세트 생성
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)

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)

# 원본 학습 피처 데이터 Shape: (455, 30) / 원본 테스트 피처 Shape: (114, 30)
print('원본 학습 피처 데이터 Shape:', X_train.shape, '원본 테스트 피처 Shape:', X_test.shape)

# 스태킹 학습 피처 데이터 Shape: (455, 4) 스태킹 테스트 피처 데이터 Shape: (114, 4)
print('스태킹 학습 피처 데이터 Shape:', Stack_final_X_train.shape, '스태킹 테스트 피처 데이터 Shape:', Stack_final_X_test.shape)

# 최종 메타 모델 학습, 예측
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)))
  • 스태킹을 이루는 모델은 최적으로 파라미터를 튜닝한 상태에서 스태킹 모델을 만드는 것이 일반적이다.

    • 스태킹 모델의 파라미터 튜닝은 개별 알고리즘 모델의 파라미터를 최적으로 튜닝하는 것을 말한다.
  • 스태킹 모델은 분류(Classification)뿐만 아니라 회귀(Regression)에도 적용 가능하다.
profile
열정 가득한 공간

0개의 댓글