AI/혼자공부하는머신러닝딥러닝

[ML] 05-3 트리의 앙상블

inthyes 2024. 1. 23. 02:09

앙상블 학습은 더 좋은 예측 결과를 만들기 위해 여러 개의 모델을 훈련하는 머신러닝 알고리즘이다.

이는 정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘이다.

 

랜덤 포레스트

랜덤 포레스트는 대표적인 결정 트리 기반의 앙상블 학습 방법이다. 부트스트랩 샘플을 사용하고 랜덤하게 일부 특성을 선택하여 트리를 만드는 특징을 지닌다.

부트스트랩이란 데이터 세트에서 중복을 허용하여 데이터를 샘플링하는 방식을 말한다. 

 

랜덤 포레스트는 위 특징들로 인해 훈련 세트에 과대적합되는 것을 막아주고 검증 세트와 테스트 세트에서 안정적인 성능을 얻을 수 있다.

 

RandomForestClassifier 클래스를 활용한 와인 분류 문제에 적용해보자.

 

첫째로 와인 데이터셋을 판다스로 불러오고 훈련 세트와 테스트 세트로 분리한다.

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)

 

 

cross_validate()함수를 사용해 교차 검증을 수행한다. return_train_score 매개변수를 True로 지정하여 검증 점수뿐만 아니라 훈련 세트에 대한 점수도 같이 반환할 수 있다. 

훈련 세트와 검증 세트의 점수를 비교하면 과대적합을 파악하는 데 용이하다.

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

훈련 세트에 다소 과대적합된 상태임을 확인할 수 있다.

 

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

랜덤 포레스트의 특성 중요도는 각 결정 트리의 특성 중요도를 취합한 것이다.

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

결정 트리에서 생성된 특성 중요도와 비교했을 때 두 번째 특성인 당도의 중요도가 감소하고 다른 특성의 중요도가 상승되었음을 확인할 수 있다. 이는 랜덤 포레스트가 특성의 일부를 랜덤하게 선택하여 결정 트리를 훈련하기 때문이다. 

결과적으로 하나의 특성에 과도하게 집중하지 않고 더 많은 특성이 훈련에 기여할 기회를 가지게 되고 과대적합을 줄이고 일반화 성능을 높이는 데 도움을 준다.

 

RandomForestClassifier는 부트스트랩 샘플에 포함되지 않고 남은 샘플인 OOB(out of bag)샘플을 사용하여 결정 트리를 평가하는 기능이 있다. 이 기능은 검증 세트의 역할과 같다.

 

oob_score 매개변수를 True로 지정하여 모델을 훈련하고 oob점수를 출력한다.

rf = RandomForestClassifier(oob_score=True, n_jobs =-1, random_state = 42)
rf.fit(train_input, train_target)
print(rf.oob_score_)

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

 

엑스트라 트리

엑스트라 트리는 랜덤 포레스트와 비슷하게 결정 트리를 사용하여 앙상블 모델을 만들지만 부트스트랩 샘플을 사용하지 않는다. 랜덤하게 노드를 분할해 과대적합을 감소시킨다.

 

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

 

랜덤 포레스트와 비슷한 결과를 얻었다. 엑스트라 트리가 무작위성이 좀 더 크기 때문에 랜덤 포레스트보다 더 많은 결정 트리를 훈련해야한다. 하지만 랜덤하게 노드를 분할하기 때문에 빠른 계산이 가능하다.

 

엑스트라 트리도 랜덤 포레스트와 같이 특성 중요도를 확인할 수 있다.

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

 

엑스트라 트리의 회귀 버전은 ExtraTreesRegressor 클래스이다.

 

그레이디언트 부스팅

그레디언트 부스팅은 랜덤 포레스트나 엑스트라 트리와 달리 결정 트리를 연속적으로 추가하여 손실 함수를 최소화하는 앙상블 방법이다.

그레디언트 부스팅은 훈련 속도가 조금 느리지만 더 좋은 성능을 기대할 수 있는 학습 방법이다.

 

사이킷런에서 제공하는 GradientBoostingClassifier을 사용하여 교차 검증 점수를 확인해보자.

 

GradientBoostingClassifier는 기본적으로 깊이가 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)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

과대적합이 거의 일어나지 않음을 확인할 수 있다. 그레디언트 부스팅은 결정 트리의 개수를 늘려도 과대적합에 매우 강하다는 장점을 갖는다. 학습률을 증가시키고 트리의 개수를 늘리면 조금 더 성능이 향상될 수 있다.

 

결정 트리 개수(n_estimators)를 500개로 늘렸지만 과대적합을 잘 억제하고 있음을 확인할 수 있다.

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

 

그레디언트 부스팅이 랜덤 포레스트보다 일부 특성(당도)에 더 집중한다.

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

 

supsample 매개변수는 트리 훈련에 사용할 훈련 세트의 비율을 정하는 역할을 한다. 기본값은 1.0으로 전체 훈련 세트를 사용하지만 1보다 작으면 훈련 세트의 일부를 사용한다. 이러한 내용은 확률적 경사 하강법이나 미니배치 경사 하강법과 유사하다.

 

 

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

히스토그램 기반 그레디언트 부스팅은  그레디언트 부스팅의 속도를 개선하여 안정적인 결과와 높은 성능으로 매우 인기가 높은 학습 방법이다.

입력 특성을 256개의 구간으로 나눠 노드를 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있다.

 

사이킷런에서 제공하는 HistGradientBoostingClassifier을 사용하여 교차 검증 점수를 확인해보자.

이 클래스는 기본 매개변수에서 안정적인 성능을 얻을 수 있다. 트리의 개수를 지정할 때 n_estimators 대신 부스팅 반복 횟수를 지정하는 max_iter을 사용한다.

from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingClassifier
hgb = HistGradientBoostingClassifier(random_state = 42)
scores = cross_validate(hgb, train_input, train_target, return_train_score = True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))

히스토그램 기반 그레디언트 부스팅의 특성 중요도를 계산하기 위해서 permutation_importance()함수를 사용한다. n_repeats 매개변수를 사용하여 랜덤하게 섞을 횟수를 지정한다.

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)

permutation_importance()함수가 반환하는 객체는 반복하여 얻은 특성 중요도(importances), 평균(importances_mean), 표준편차(importances_std)를 포함한다.

 

테스트 세트에서 특성 중요도를 계산하면 아래와 같은 결과가 출력된다.

result = permutation_importance(hgb, test_input, test_target, n_repeats = 10, random_state = 42, n_jobs = -1)
print(result.importances_mean)

테스트 세트의 결과를 보면 그레디언트 부스팅과 비슷하게 조금 더 당도에 집중하고 있다는 것을 알 수 있다. 이런 분석을 통해 ㅁ도ㅔㄹ을 실전에 투입했을 때 어떤 특성에 관심을 둘지 예상할 수 있다.

 

테스트 세트에서의 성능을 최종적으로 확인해보자.

hgb.score(test_input, test_target)

이전에 수행한 랜덤 서치에 비해 1% 높은 정확도를 얻었다. 앙상블 모델은 확실히 단일 결정 트리보다 좋은 결과를 얻을 수 있다.

'AI > 혼자공부하는머신러닝딥러닝' 카테고리의 다른 글

[ML] 06-2 k-평균  (1) 2024.01.23
[ML] 06-1 군집 알고리즘  (1) 2024.01.23
[ML] 05-2 교차 검증과 그리드 서치  (1) 2024.01.22
[ML] 05-1 결정 트리  (1) 2024.01.22
[ML] 04-2 확률적 경사하강법  (1) 2024.01.21