본문 바로가기
Python/머신러닝+딥러닝 Ⅰ

Ensemble Model

by Mr.DonyStark 2024. 3. 25.

□ 정형 데이터를 다루는데 가장 뛰어난 성과를 내는 알고리즘이 앙상블 학습(ensemble learning)
□ 앙상블 학습의 대표적인 모델을 랜덤 포레스트(Random Forest)를 들 수 있음.
□ 랜덤 포레스트는 결정 트리를 랜덤하게 만들어 결정트리(나무)의 숲을 만듬.
□ 그리고 각 결정 트리의 예측을 사용해 최종 예측을 만듬.
□ 데이터를 랜덤하게 만드는데 이 데이터를 만드는 방법이 독특. 우리가 입력한 훈련 데이터에서 랜덤하게 샘플을 추출하여 훈련 데이터를 만드는데 이 때 한 샘플이 중복되어 추출될수 있음.
□ 이러한 샘플을 중복이 허용되는 샘플, 즉, 부트스트랩 샘플(bootstrap sample)이라고 부름.
□ 랜덤하게 선택한 샘플과 특성을 사용하기 때문에 훈련 세트에 과대적합되는 것을 막아주고 검증 세트와 테스트 세트에서 안정적인 성능을 만들 수 있음.

□ 예제

  ○ 랜덤포레스트 : 부트스트랩 샘플링

#라이브러리 호출
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

#데이터 불러오기
wine = pd.read_csv("https://bit.ly/wine_csv_data")

data = wine[["alcohol", "sugar", "pH"]].to_numpy() #인풋데이터 저장
target = wine["class"].to_numpy() #타겟데이터 저장

#트레이닝/테스트셋 구축
train_input, test_input, train_target, test_target = train_test_split(data, target, test_size=0.2, random_state=42)

#모델생성 + 교차검증
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier
#-모델객체생성
rf = RandomForestClassifier(n_jobs=-1, random_state=42)  #n_jobs로 CPU 코어 속성지정
scores = cross_validate(rf, train_input, train_target, return_train_score = True, n_jobs=-1) #return_train_score 속성으로 학습셋으로 트레이닝한 정확도(score) 표시
#-기본적으로 교차검증 k-fold 5번을 시행하므로 평균을 내어 정확도산출
#--트레이닝셋 정확도 출력
print(f"교차검증(k-fold)트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"교차검증(k-fold)테스트셋 정확도 : {np.mean(scores['test_score'])}")
#-모델학습
rf.fit(train_input,train_target)
print(f"자체 트레닝셋 정확도 : {rf.score(train_input, train_target)}")
print(rf.feature_importances_) #데이터 속성별로 해당 모델이 중요하게 생각한 수치

 

  ○ 랜덤포레스트 : OOB

    - 부트스트랩 샘플을 제외한 나머지 샘플을 OOB(Out Of Bag) 샘플이라고 부르는데 이 남는 샘플을 사용하여 부트스트랩 샘플로 훈련한 결정 트리를 평가할 수 있음. 즉, 검정 세트의 역할을 대신함.
    - OOB 점수를 사용하면 교차 검증을 대신할 수 있어서 결과적으로 훈련세트에서 더많은 샘플 사용할 수 있음.

#학습모델 객체 생성 + oob_score 사용
rf = RandomForestClassifier(oob_score = True, n_jobs = -1, random_state = 42)
#학습
rf.fit(train_input, train_target)
#oob를 활용한 정확도 출력
print(f"oob를 활용한 학습 정확도 : {rf.oob_score_}")

 

  ○ 엑스트라트리

    - 엑스트라트리(Extra Tree)
    - 랜덤 포레스트와 매우 비슷하게 동작.
    - 기본적으로 100개의 결정트리 훈련.
    - 랜덤 포레스트와 동일하게 결정트리가 제공하는 대부분의 매개변수 지원.
    - 랜덤포레스트와 엑스트라트리의 차이점은 부트스트랩 샘플을 사용하지 않음.
    - 랜덤포레스트의 경우 가장 좋은 속성을 찾아 분할하지만, 엑스트라 트리는 전체 특성중에 일부 특성을 랜덤하게 선택하여 노드분할함.
    - 하나의 결정트리에서 특성을 무작위로 분할하게되면 성능은 낮아지지만 많은 트리를 앙상블 하기 때문에 과대적합을 막고 검증세트의 점수를 높일수 있음.

from sklearn.ensemble import ExtraTreesClassifier
#모델생성
et = ExtraTreesClassifier(n_jobs=-1, random_state=42)
#모델교차검증
scores = cross_validate(et, train_input, train_target, return_train_score= True, n_jobs=-1) #return_train_score 속성으로 학습셋으로 트레이닝한 정확도(score) 표시
#-모델 정확도
#--트레이닝셋 정확도 출력
print(f"트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"테스트셋 정확도 : {np.mean(scores['test_score'])}")
#=모델학습
et.fit(train_input, train_target)
print(f"자체 트레닝셋 정확도 : {et.score(train_input, train_target)}")
print(et.feature_importances_) #데이터 속성별로 해당 모델이 중요하게 생각한 수치 →

 

  ○ 그래디언트 부스팅

    - 그래디언트 부스팅Gradient Boosting
    - 깊이가 얕은 결정트리를 사용하여 이전 트리의 오차를 보완하는 방식으로 앙상블하는 방법.
    - 기본적으로 깊이가 3인 결정트리를 100개 사용.
    - 깊이가 얕은 결정트리를 사용하기에 과대적합에 강하고 일반적으로 높은 일반화 성능을 기대할 수 있음.
    - 학습률 매개변수로 속도를 조절하여 확률적 경사하강법을 진행함.
    - 그레디언트 부스팅은 결정트리의 개수를 늘려도 과대적합에 매우 강함.

from sklearn.ensemble import GradientBoostingClassifier
#-모델 객체생성
gb = GradientBoostingClassifier(random_state=42)
#-교차검증
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1) #return_train_score 속성으로 학습셋으로 트레이닝한 정확도(score) 표시
#--트레이닝셋 정확도 출력
print(f"트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"테스트셋 정확도 : {np.mean(scores['test_score'])}")

 

  ○ 그래디언트 부스팅 : 트리개수 및 학습률 매개변수 조정

from sklearn.ensemble import GradientBoostingClassifier
#-모델 객체생성
gb = GradientBoostingClassifier(n_estimators=500, learning_rate=0.2, random_state=42)
#-교차검증
scores = cross_validate(gb, train_input, train_target, return_train_score=True, n_jobs=-1) #return_train_score 속성으로 학습셋으로 트레이닝한 정확도(score) 표시
#--트레이닝셋 정확도 출력
print(f"트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"테스트셋 정확도 : {np.mean(scores['test_score'])}")
#=모델학습
gb.fit(train_input, train_target)
print(f"자체 트레닝셋 정확도 : {gb.score(train_input, train_target)}")
print(gb.feature_importances_) #데이터 속성별로 해당 모델이 중요하게 생각한 수치


  ○ 히스토그램 기반 그레이디언트 부스팅

    - 정형 데이터를 다루는 머신러닝  알고리즘 중에 가장 인기가 높은 알고리즘.
    - 입력특성을 기본적으로 256개의 구간으로 나눠 노드를 분할할때 최적의 분할을 매우 빠르게 찾음.
    - 예를 들면 현재 데이터에서 알콜, 당도, pH 속성별 수치성 값을 256개의 범위로 나눈후 노드를 분할하는 것을 의미.

from sklearn.ensemble import HistGradientBoostingClassifier
hgb = HistGradientBoostingClassifier(random_state=42)
scores = cross_validate(hgb, train_input, train_target, return_train_score=True)  #return_train_score 속성으로 학습셋으로 트레이닝한 정확도(score) 표시
#--트레이닝셋 정확도 출력
print(f"트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"테스트셋 정확도 : {np.mean(scores['test_score'])}")

 

※ 히스트로그램 기반 그레이디언트 부스팅은 다른 모델과 달리 feature_importances_를 못뽑음.
따라서 permutation_importance()가 반환하는 중요도, 평균, 표준편차를 활용하여 특성 중요도를 계산할 수 있음.

from sklearn.inspection import permutation_importance

#트레이닝셋
#-학습
hgb.fit(train_input, train_target)
#-속성별 중요도
result = permutation_importance(hgb, train_input, train_target, n_repeats=10, random_state=42, n_jobs=-1)
print(f"그레이디언트 부스팅 트레이닝셋 중요도 : {result.importances_mean}") #속성별 중요도에대한 평균

#테스트셋
#-학습
result = permutation_importance(hgb, test_input, test_target, n_repeats=10, random_state= 42, n_jobs=-1)
print(f"그레이디언트 부스팅 테스트셋 중요도 : {result.importances_mean}") #속성별 중요도에대한 평균
#-정확도
print(f"자체 테스트셋 정확도 : {gb.score(test_input, test_target)}")

 

  ○  또다른 방법의히스토그램 기반 그레이디언트 부스팅의 회귀버전 : XGBClassifier, LightGBM

    - XGBClassifier

from xgboost import XGBClassifier

xgb = XGBClassifier(tree_method = "hist", random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True)

#--트레이닝셋 정확도 출력
print(f"트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"테스트셋 정확도 : {np.mean(scores['test_score'])}")

    - LightGBM (Microsoft 사에서 개발한 라이브러리)

from lightgbm import LGBMClassifier

#모델생성
lgb = LGBMClassifier(random_state=42)
#정확도
scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-2)
#--트레이닝셋 정확도 출력
print(f"트레이닝셋 정확도 : {np.mean(scores['train_score'])}")  
#--테스트셋 정확도 출력
print(f"테스트셋 정확도 : {np.mean(scores['test_score'])}")