[혼공머신]5-3. 트리의 앙상블

Seyi·2025년 1월 28일
0

이번 챕터에서는 앙상블 학습이 무엇인지 이해하고 다양한 앙상블 학습 알고리즘을 실습해보겠습니다~❕



1. 정형 데이터와 비정형 데이터

정형 데이터

지금까지 공부하면서 다뤘던 생선의 특성과 타겟 CSV 데이터, 와인 CSV 파일 등 어떤 정해진 구조로 되어있는 데이터를 정형 데이터라고 합니다. 주로 CSV나 엑셀등을 사용해 저장합니다.

비정형 데이터

반면에 비정형 데이터는 텍스트, 이미지, 소리 등 정해진 형태로 저장하기 어려운 데이터를 말합니다.

지금까지 배운 머신러닝 알고리즘은 주로 정형 데이터를 다루며, 정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘은 앙상블 학습입니다.




2. 랜덤 포레스트

랜덤포레스트

  • 대표적인 결정 트리 기반의 앙상블 학습 방법
  • 부트스트랩 샘플을 사용하고 랜덤하게 일부 특성을 선택하여 트리를 만듦

랜덤 포레스트는 결정 트리를 랜덤하게 만들어 결정 트리(나무)의 숲을 만듭니다.
그리고 각 결정 트리의 예측을 사용해서 최종 예측을 합니다.

먼저 랜덤 포레스트는 각 트리를 훈련하기 위해 데이터를 랜덤하게 만듭니다. 이 때, 예를 들어 1000개의 샘플 중에 100개의 샘플을 뽑는다면

  1. 1000개의 샘플이 들어있는 가방에서 1개의 샘플을 뽑고
  2. 뽑은 1개의 샘플을 다시 가방에 넣은 후
  3. 1000개 중에 또 다시 1개를 뽑고
  4. 100개의 샘플이 추려질 때까지 위 과정을 반복합니다.

이렇게 중복해서 샘플을 추출하는 방식을 부트스트랩이라고 합니다.

부트스트랩

  • 데이터 세트에서 중복을 허용하여 데이터를 샘플링하는 방식

RandomForestClassifier 클래스틑 기본적으로 전체 특성 개수의 제곱근만큼의 특성을 선택합니다. 회귀 모델인 RandomForestRegressor는 전체 특성을 사용합니다.

사이킷런의 랜덤 포레스트 모델은 기본적으로 100개의 결정 트리를 훈련합니다.
그 다음 분류일 때는 각 트리의 클래스별 확률의 평균을 구하여 가장 높은 확률을 가진 클래스를 예측으로 삼습니다. 회귀일 때는 각 트리의 예측을 평균합니다.


실습 예제

랜덤포레스트를 사용해서 와인을 분류하는 문제를 해결해보겠습니다.

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)
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

cross_validate( ) 함수를 사용해서 교차 검증을 수행합니다.
출력된 결과를 보면 훈련세트에 과대적합된 것으로 보입니다.

RandomForestClassifier 클래스의 n_jobs 매개변수

  • CPU 사용 개수 지정
  • -1로 지정하면 모든 CPU 코어를 사용

cross_validate( ) 의 매개변수

  • n_jobs : -1로 지정하면 최대한 병렬로 교차 검증을 수행
  • return_train_score : 검증 점수뿐만 아니라 훈련 세트에 대한 점수도 함께 반환(기본값 False)

랜덤 포레스트는 결정 트리의 앙상블이기 때문에 DecisionTreeClassifier가 제공하는 매개변수를 제공합니다.

또한 결정 트리의 큰 장점 중 하나인 특성 중요도를 계산합니다. 랜덤포레스트의 특성 중요도는 각 결정 트리의 특성 중요도를 취합한 결과입니다.

랜덤 포레스트 모델을 훈련 세트에 대해 학습한 후 특성 중요도를 출력해보겠습니다.

rf.fit(train_input, train_target)
print(rf.feature_importances_)

[0.23167441 0.50039841 0.26792718]

이 결과를 앞장에서 '결정 트리'를 통해 출력한 특성 중요도와 비교해보겠습니다.
[0.12345626 0.86862934 0.0079144 ]

각각 [알코올 도수, 당도, pH]였는데, 두 번째 특성인 당도의 중요도가 감소하고 알코올 도수와 pH 특성의 중요도가 상승했습니다. 그 이유는 랜덤 포레스트가 특성의 일부를 랜덤하게 선택하여 결정트리를 훈련하기 때문입니다. 따라서 하나의 특성에 과도하게 집중하지 않고 다양한 특성이 훈련에 기여할 기회를 얻게됩니다. 이는 과대 적합을 줄이고 일반화 성능을 높이는 데 도움이 됩니다. 👍

RandomForestClassifier에는 부트스트랩 샘플에 포함되지 않고 남는 샘플인 OOB(out of bag) 샘플을 사용하여 부트스트랩 샘플로 훈련한 결정트리를 평가할 수 있습니다.

rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

rf.fit(train_input, train_target)
print(rf.oob_score_)

0.8934000384837406

oob_score

  • RandomForestClassifier 의 매개변수로 OOB 샘플에 대한 검증 점수 확인
  • 기본값은 False

교차 검증에서 얻은 점수와 매우 비슷한 결과를 얻었습니다. OOB 점수를 사용하면 교차 검증을 대신할 수 있어서 결과적으로 훈련 세트에 더 많은 샘플을 사용할 수 있습니다.




3. 엑스트라 트리

엑스트라 트리 는 랜덤 포레스트와 매우 비슷하게 동작하는 또 다른 앙상블 학습 기법입니다.

엑스트라 트리

  • 결정트리를 사용하여 앙상블 모델을 만듦
  • 부트스트랩 샘플을 사용하지 않음
  • 랜덤하게 노드를 분할하여 과대적합을 감소

엑스트라 트리는 결정트리를 만들 때 전체 훈련 세트 사용합니다. 대신 노드를 분할할 때 가장 좋은 분할을 찾는 것이 아니라 무작위로 분할합니다.

DecisionTreeClassifier에서 splitter의 매개변수를 'random'으로 지정하면 엑스트라 트리가 사용하는 결정트리를 구현할 수 있습니다. 사이킷런에서는 ExtraTreesClassifier 클래스를 제공합니다.

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]

엑스트라 트리의 특성 중요도를 출력했습니다. 엑스트라 트리 역시 결정 트리보다 당도에 대한 의존성이 낮아졌습니다.




4. 그래디언트 부스팅

그래디언트 부스팅

  • 랜덤포레스트나 엑스트라 트리와 달리 결정 트리를 연속적으로 추가하여 손실 함수를 최소화하는 앙상블 기법
  • 훈련 속도가 느리지만 좋은 성능을 기대할 수 있음

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

  • 그래디언트 부스팅의 속도를 개선하여 안정적인 결과와 높은 성능을 보이는 기법

그래디언트 부스팅은 깊이가 얕은 결정 트리를 사용하여 이전트리의 오차를 보완하는 방식으로 앙상블하는 기법입니다. GradientBoostingClassifier를 사용하며 기본적으로 깊이가 3인 결정 트리를 100개 사용합니다.

그래디언트라는 이름에서 알 수 있듯 경사 하강법을 사용하여 트리를 앙상블에 추가합니다. 분류에서는 로지스틱 손실 함수를, 회귀에서는 평균제곱오차 함수를 사용합니다.

그래디언트 부스팅은 깊이가 얕은 결정트리를 사용해서 계속 결정 트리를 추가하면서 손실함수가 낮은 곳을 찾아 이동합니다.


실습 예제

와인 데이터셋을 사용해서 GradientBoostingClassifier를 학습하고 교차검증 점수를 확인해보겠습니다.

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

결정 트리 개수를 500까지 늘리고 학습률을 올려도 과대적합이 억제되고 있습니다.

gb.fit(train_input, train_target)
print(gb.feature_importances_)

[0.15887763 0.6799705 0.16115187]

특성 중요도를 확인하니 그래디언트 부스팅이 랜덤포레스트보다 당도에 더 집중한다는 점을 알 수 있습니다.

일반적으로 그래디언트 부스팅이 랜덤포레스트보다 더 높은 성능을 얻을 수 있지만 순서대로 트리를 추가하기 때문에 훈련 속도가 느립니다. 히스토그램 기반 그래디언트 부스팅은 그래디언트 부스팅의 속도와 성능을 개선한 알고리즘입니다.

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

히스토그램 기반 그래디언트 부스팅은 특성을 256개 구간으로 나눠 노드를 분할할 때 최적의 분할을 빠르게 찾아냅니다. 256개 구간 중에서 하나를 떼어 두고 누락된 값을 위해서 사용합니다.

HistGradientBoostingClassfier 클래스를 사용해서 구현해보겠습니다.

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

과대적합을 잘 억제하면서 그래디언트 부스팅 모델보다 성능이 높아졌네요!

max_iters

  • HistGradientBoostingClassfier에서 부스팅 반복 횟수를 지정하는 매개변수

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]

특성 중요도를 계산하기 위해 permutation_importance( ) 함수를 사용했습니다.

n_repeats

  • 랜덤하게 섞을 횟수를 지정하는 매개변수
  • 기본값은 5

permutation_importance( ) 함수

  • 특성 중요도(importance), 평균(importance_mean), 표준 편차(importances_std) 를 담고 있음
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

사이킷런 외에도 그래디언트 부스팅을 구현한 라이브러리가 여러 개 있는데, 그 중 하나가 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.9558403027491312 0.8782000074035686

tree_method 매개변수를 'hist'로 지정하면 히스토그램 기반 그래디언트 부스팅을 사용할 수 있습니다.


LightGBM

또 다른 라이브러리로는 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



여기까지해서 앙상블 알고리즘에 대해서 공부했습니다!
지금까지는 입력데이터와 타깃데이터를 갖춘 데이터로 머신러닝 학습을 했는데요,
다음장에서는 타깃이 없는 데이터를 학습하는 방법에 대해서도 공부해보겠습니다~~!

자료 출처: 한빛 미디어

profile
머신러닝 딥러닝 학습기록

0개의 댓글

관련 채용 정보