본문 바로가기
Machine Learning

[혼자 공부하는 머신러닝+딥러닝] 트리의 앙상블

by 가론노미 2023. 5. 14.
[혼자 공부하는 머신러닝+딥러닝] 책의 내용을 정리한 글입니다.

개념

앙상블 학습

: 더 좋은 예측 결과를 만들기 위해 여러 개의 모델을 훈련하는 머신러닝 알고리즘

→ CSV, 데이터베이스, 엑셀 과 같은 정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘

랜덤 포레스트

: 대표적인 결정 트리 기반의 앙상블 학습 방법

  • 훈련 데이터로 부트스트랩 샘플을 사용하고, 노드를 분할할 때 랜덤하게 일부 특성을 선택하여 트리를 만드는 것이 특징
    • 부트스트랩 샘플 - 훈련 데이터에서 중북 하여 랜덤 하게 샘플을 추출
    • 기본적으로 100개의 결정 트리를 위 같은 방식으로 훈련한 뒤 분류는 가장 높은 확률을 가진 클래스로, 회귀는 각 트리의 예측을 평균으로 결과를 냄
  • 랜덤하게 선택한 샘플과 특성을 사용하기 때문에 훈련 세트에 과대적합되는 것을 막아주고 안정적인 성능을 얻을 수 있음
  • 부트스트랩 샘플에 포함되지 않고 남은 샘플인 OOB(out of bag) 샘플로 검증 가능

엑스트라 트리

: 랜덤 포레스트와 비슷하게 결정 트리 기반의 앙상블 학습 방법

  • 랜덤 포레스트와의 차이점은 부트스트랩 샘플을 사용하지 않는다는 점 → 결정 트리를 만들 때 전체 훈련 세트를 사용
  • 대신 노드를 분할할 때 랜덤하게 분할하여 과대적합을 감소
  • 장점
    • 랜덤하게 노드를 분할하기 때문에 계산 속도가 빠름
  • 단점 
    • 보통 엑스트라 트리가 무작위성이 좀 더 크기에 랜덤 포레스트가 더 많은 결정 트리를 훈련해야 함

그레이디언트 부스팅

: 랜덤 포레스트나 엑스트라 트리와 달리 깊이가 얕은 결정 트리를 연속적으로 추가하여 손실 함수를 최소화하는 앙상블 학습 방법

  • 기본적으로 깊이가 3인 결정 트리 100개를 사용
  • 경사 하강법을 사용하여 트리를 앙상블에 추가 (분류에서는 로지스틱 손실 함수, 회귀에서는 평균 제곱 오차 함수 사용)
  • 훈련 속도는 조금 느리지만 더 좋은 성능을 기대할 수 있음

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

: 훈련 데이터를 256개의 구간으로 변환하여 사용함으로써 그레이디언트 부스팅의 속도와 성능을 개선한 알고리즘

  • 안정적인 결과와 높은 성능으로 가장 뛰어난 앙상블 학습으로 평가받음
  • 히스토그램 기반 그레이디언트 부스팅의 특성 중요도를 계산하기 위해서는 permutation_importance() 함수를 사용
  • 사이킷런 이외에 해당 알고리즘을 구현한 다른 라이브러리 - XGBoost, LightGBM

코드 작성

다양한 앙상블 학습 방법들을 사용하여 모델을 훈련시켜 보자

와인 데이터 준비

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)
# 교차 검증 수행 - return_train_score True로 지정 시 검증 점수와 훈련 세트 점수를 같이 반환
scores = cross_validate(rf, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.9973541965122431 0.8905151032797809

# 훈련 세트로 훈련한 후 특성 중요도 출력
rf.fit(train_input, train_target)
print(rf.feature_importances_)
# => [0.23167441 0.50039841 0.26792718]

# OOB 샘플을 사용하여 자체적으로 모델을 평가하는 점수 출력 (교차 검증을 대신 할 수 있음)
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

rf.fit(train_input, train_target)
print(rf.oob_score_)
# => 0.8934000384837406

엑스트라 트리를 사용한 모델 학습

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)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.9974503966084433 0.8887848893166506

# 특성 중요도 출력
et.fit(train_input, train_target)
print(et.feature_importances_)
# => [0.20183568 0.52242907 0.27573525]

그레이디언트 부스팅을 사용한 모델 학습

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)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.8881086892152563 0.8720430147331015

# 결정 트리의 개수를 늘려도 과대적합에 강하기 때문에 학습률을과 트리의 개수를 증가하면 성능 향상이 가능
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)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.9464595437171814 0.8780082549788999

# 특성 중요도 출력
gb.fit(train_input, train_target)
print(gb.feature_importances_)
# => [0.15872278 0.68010884 0.16116839]

히스토그램 기반 그레이디언트 부스팅을 사용한 모델 학습

from sklearn.ensemble import HistGradientBoostingClassifier

hgb = HistGradientBoostingClassifier(random_state=42)
scores = cross_validate(hgb, train_input, train_target, return_train_score=True, n_jobs=-1)

# 과대적합을 잘 억제하면서 그레이디언트 부스팅보다 조금 더 높은 성능을 제공
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.9321723946453317 0.8801241948619236

# 특성 중요도 출력
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(result.importances_mean)
# => [0.08876275 0.23438522 0.08027708]

# 테스트 세트에서의 특성 중요도 출력
result = permutation_importance(hgb, test_input, test_target, n_repeats=10,
                                random_state=42, n_jobs=-1)
print(result.importances_mean)
# => [0.05969231 0.20238462 0.049]

# 테스트 세트에서의 성능 확인
hgb.score(test_input, test_target)
# => 0.8723076923076923

사이킷런 이외에 히스토그램 기반 그레이디언트 부스팅을 구현한 다른 라이브러리를 사용해 모델 학습

# XGBoost를 사용하여 교차 검증 점수 확인
from xgboost import XGBClassifier

xgb = XGBClassifier(tree_method='hist', random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.9555033709953124 0.8799326275264677

# LightGBM을 사용하여 교차 검증 점수 확인
from lightgbm import LGBMClassifier

lgb = LGBMClassifier(random_state=42)
scores = cross_validate(lgb, train_input, train_target, return_train_score=True, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# => 0.935828414851749 0.8801251203079884

이 장에서 사용된 핵심 패키지와 함수

scikit-learn

  • RandomForestClassifier
    • 랜덤 포레스트 분류 클래스
    • n_estimators - 앙상블을 구성할 트리의 개수를 지정 (기본값 - 100)
    • criterion - 지니 불순도와 엔트로피 불순도 중 선택 가능 (기본값 - 'gini')
    • max_depth - 트리가 성장할 최대 깊이를 지정
    • min_sample_split - 노드를 나누기 위한 최소 샘플 개수 (기본값 - 2)
    • max_features - 최적의 분할을 위해 탐색할 특성의 개수를 지정 (기본값 - 'auto'로 특성 개수의 제곱근)
    • bootstrap - 부트스트랩 샘플을 사용할지 지정 (기본값 - True)
    • oob_score - OOB 샘플을 사용하여 훈련한 모델을 평가할지 지정 (기본값 - False)
    • n_jobs - 병렬 실행에 사용할 CPU 코어 수를 지정 (기본값 - 1)
  • ExtraTreesClassifier
    • 엑스트라 트리 분류 클래스
    • bootstrap - 부트스트랩 샘플을 사용할지 지정 (기본값 - False)
    • bootstrap을 제외한 나머지 매개변수는 랜덤 포레스트와 동일
  • GradientBoostingClassifier
    • 그레이디언트 부스팅 분류 클래스
    • loss - 손실 함수를 지정 (기본값 - 로지스틱 손실 함수를 의미하는 'deviance')
    • learning_rate - 트리가 앙상블에 기여하는 정도를 조정 (기본값 - 0.1)
    • n_estimators - 사용할 훈련 세트의 샘플 비율을 지정 (기본값 - 1.0)
    • subsample - 훈련 세트의 샘플 비율을 지정 (기본값 - 1.0)
    • max_depth - 개별 회귀 트리의 최대 깊이 (기본값 - 3)
  • HistGradientBoostingClassifier
    • 히스토그램 기반 그레이디언트 부스팅 분류 클래스
    • learning_rate - 학습률 또는 감쇠율이라고 하며 1.0인 경우 감쇠가 전혀 없음 (기본값 - 0.1)
    • max_iter - 부스팅 단계를 수행하는 트리의 개수 (기본값 - 100)
    • max_bins - 입력 데이터를 나눌 구간의 개수로 255보다 크게 지정할 수 없고 이 중 1개의 구간이 누락된 값을 위해 추가됨 (기본값 - 255)