혼공단/혼공단 5기

혼자 공부하는 머신러닝 + 딥러닝 5장 - 트리의 앙상블

하양훈 2021. 2. 19. 11:36
반응형

1. 정형 데이터와 비정형 데이터 & 앙상블 학습

 

<정형 데이터와 비정형 데이터>

 

- 정형 데이터 : 구조가 정해져 있고 가지런히 정리된 데이터

- 비정형 데이터 : 데이터베이스나 엑셀로 표현하기 어려운 것들. 텍스트, 사진, 음성파일등이 해당된다.

 

<앙상블 학습>

 

- 다양한 분류 알고리즘(주로 결정 트리를 기반)을 합쳐서 학습을 진행하는 방법

- 랜덤 포레스트, 엑스트라 트리, 그레이디언트 부스팅 등이 있다.

 

 

 2. 랜덤 포레스트

 

- 결정 트리를 랜덤하게 만들어 결정 트리의 숲을 만든다. 그리고 각 결정 트리의 예측을 사용해 최종 예측을 만든다.

- 랜덤 포레스트는 각 트리를 훈련하기 위한 데이터를 랜덤하게 만드는게 이때 부트스트랩 샘플을 사용한다.

 

<부트스트랩 샘플>

 

- 전체 세트에서 뽑았던 샘플을 다시 넣어서 복원 추출을 하게 하는 것. 이 경우 중복이 적용된다.

- 보통 부트 스트랩 방식이라고 한다.

 

- 또한 각 노드를 분할할때 전체 특성 중 일부 특성을 무작위로 고른 다음 이 중에서 최선의 분할을 찾는다.

- 분류 모델인 RandomForestClassifier는 기본적으로 전체 특성 개수의 제곱근 만큼 특성을 선택한다.

 

<실습 코드>

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

 

- 코드의 사용방법은 다른 학습모델과 큰 차이가 없다.

- 랜덤 포레스트는 결정 트리의 앙상블이기 때문에 특성 중요도를 계산해서 출력할 수 있다.

 

# 특성 중요도 계산
rf.fit(train_input, train_target)
print(rf.feature_importances_)

 

- RandomForestClassifier에는 자체적으로 모델을 평가하는 점수를 얻을 수 있다.

- 부트스트래핑을 할때,부트스트랩 샘플에 포함되지 않고 남은 샘플(=OOB샘플)로 훈련한 결정트리를 평가할 수 있다.(이때 OOB샘플은 검증 세트의 역할을 하는 셈이다) 이 점수를 얻으려면 매개변수 oob_score를 True로 지정해야 한다.

 

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

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

 

 

3. 엑스트라 트리

 

- 랜덤 포레스트와 비슷하게 동작하지만, 엑스트라 트리는 부트스트랩 샘플을 사용하지 않고 결정트리를 만들때 전체 훈련 세트를 사용한다.

- 대신 노드를 분할할때 무작위로 분할하게 된다(spliter=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']))

 

4. 그레이디언트 부스팅(Gradient Boosting)

 

- 깊이가 얕은 결정 트리를 사용하여 이진트리의 오차를 보완하는 방식으로 앙상블 하는 방법

- 경사하강법을 사용하여 트리를 앙상블에 추가하며, 분류에서는 로지스틱 손실 함수를, 회귀에서는 평균 제곱 오차 함수를 사용한다.

- 일반적으로 그레이디언트 부스팅이 랜덤 포레스트보다 조금 더 높은 성능을 얻을 수 있다. 하지만 순서대로 트리를 추가하기 때문에 훈련 속도가 느리다.(그래서 GradientBoostingClassifier에는 n_jobs가 없다.)

- 사이킷런에서 제공하는 그레이디언트 부스팅 클래스는 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']))

 

- 결정 트리에는 아래와 같은 매개변수들이 있다.

1) n_estimators : 사용할 결정 트리의 개수, 기본값은 100이다.

2) learning_rate: 학습률, 기본값은 0.1이다.

 

 

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

 

- 입력 특성을 256개의 구간으로 나누고, 그 구간중에서 하나를 떼어놓고 누락된 값을 위해서 사용한다.

- 사이킷런에서 제공하는 히스토그램 기반 그레이디언트 부스팅 클래스는 HistGradientBoostingClassifier이다.

 

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, n_jobs=-1)

print(np.mean(scores['train_score']), np.mean(scores['test_score']))

 

- 히스토그램 기반 그레이디언트 부스팅의 회귀버전은 HistGradientBoostingRegressor에 구현되어 있다.

- 사이킷런 말고도 히스토그램 기반 그레이디언트 부스팅 알고리즘을 구현한 라이브러리로 XGBoost, LightGBM등이 있다.

 

 

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

 

- 여러개의 Decision Tree를 조합해서 사용하는 Ensemble 알고리즘

- XGBoost에서 tree_method를 hist로 지정하면 히스토그램 기반 그레이디언트 부스팅 알고리즘을 쓸 수 있다.

 

 

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

 

-  LightGBM의 경우에는 최대 손실값을 가지는 노드를 중심으로 계속해서 분할하는 '리프 중심 트리 분할(leaf-wise)' 방식을 사용한다.

- 따라서 트리가 깊어지기위해 소요되는 시간과 메모리를 많이 절약할 수 있다.

- 다만 적은 데이터에 대한 과적합(overfitting)이 발생하기 쉽다

 

 

 

<전체 소스 코드>

 

링크 : bit.ly/hg-05-3

 

Google Colaboratory

 

colab.research.google.com

 

반응형