Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

kang's study

11일차 : 트리의 앙상블 본문

[학습 공간]/[혼공머신러닝]

11일차 : 트리의 앙상블

보끔밥0302 2022. 3. 3. 06:54

 

 

 

 

 

트리의 앙상블 (tree ensemble)

 
정형 데이터에서 가장 뛰어난 성능을 내는 머신러닝 알고리즘 중 하나
 

랜덤포레스트 (RandomForest)

결정트리를 랜덤하게 만들어 숲을 이룬다.
사이킷런에 구현된 앙상블 학습 알고리즘으로 학습

In [1]:
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
In [2]:
# 데이터 불러오기
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)
 

랜덤 포레스트 훈련방법

부트스트랩 샘플 :

훈련세트와 크기를 같게 만든다.
훈련데이터에서 중복 가능하게 하여 랜덤하게 샘플을 추출한다.
샘플의 대표성을 줄이는 과정

특성의 개수 :

RandomForestClassifier는 전체 특성 개수의 제곱근만큼의 특성을 선택
ex 4개의 특성이라면 노드마다 2개를 랜덤하게 선택하여 사용해 최선의 분할을 찾음
RandomForestRegressor는 전체 특성 개수를 사용한다.

In [3]:
from sklearn.model_selection import cross_validate
from sklearn.ensemble import RandomForestClassifier
In [4]:
# 교차검증
# 랜덤포레스트는 기본적으로 100개의 결정트리를 사용
rf = RandomForestClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(rf, train_input, train_target, return_train_score=True,
                        n_jobs=-1)
# train_score 출력 가능
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
 
0.9973541965122431 0.8905151032797809
In [5]:
rf.fit(train_input, train_target) # 모델을 훈련
print(rf.feature_importances_)
 
[0.23167441 0.50039841 0.26792718]
 
OOB(out of bag)샘플 : 부트스트랩 샘플에 포함되지 않고 남겨진 샘플들
In [6]:
# 남는 샘플로 검증세트 역할을 해본다
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)

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

엑스트라트리

결정트리를 만들 때 전체 훈련세트를 사용한다.
노드분할은 무작위로 한다. 결정트리에서 splitter='random'
무작위성을 주입하여 트리의 성장을 억제하는 방법이 다르다.
각 특성을 랜덤하게 분할하여 가장 좋은 불순도를 나타내는 하나를 찾는다.
속도가 빠르나 성능은 랜덤보다 트리를 늘려야 좋은 성능을 낼 수 있다.
In [7]:
from sklearn.ensemble import ExtraTreesClassifier 
# s가 있다 주의
In [8]:
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
In [9]:
et.fit(train_input, train_target)
print(et.feature_importances_)
 
[0.20183568 0.52242907 0.27573525]
 

고려해야 할 특성의 개수가 많을 때 엑스트라 트리의 장점이 나타난다.
랜덤하게 노드를 분할하기에 계산 속다가 빠르다

 

그레이디언트 부스팅

분류든 회귀든 결정트리 회귀모형을 사용한다.
(깊이가 얕은 결정트리를 연속하여 추가하여)이전 트리의 손실을 보완하는 식으로 오차를 줄여나가는 학습을 한다.
깊이가 3인 결정트리 100개를 기본으로 사용
경사하강법 : 손실 함수를 산으로 정의하여 가장 낮은 곳을 찾아 내려오는 과정
In [10]:
from sklearn.ensemble import GradientBoostingClassifier
In [11]:
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
In [12]:
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
In [13]:
gb.fit(train_input, train_target)
print(gb.feature_importances_)
 
[0.15872278 0.68010884 0.16116839]
 

히스토그램 기반 부스팅

훈련데이터를 256개 정수 구간으로 나누어 빠르고 높은 성능을 냄
 

사이킷런

In [14]:
# 사이킷런 1.0 버전 아래에서는 다음 라인의 주석을 해제하고 실행하세요.
from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import HistGradientBoostingClassifier
 
C:\Users\kang\anaconda3\lib\site-packages\sklearn\experimental\enable_hist_gradient_boosting.py:16: UserWarning: Since version 1.0, it is not needed to import enable_hist_gradient_boosting anymore. HistGradientBoostingClassifier and HistGradientBoostingRegressor are now stable and can be normally imported from sklearn.ensemble.
  warnings.warn(

 

In [15]:
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
 

과대적합을 잘 억제하고 그레이디언트 부스팅보다 조금 더 높은 성능을 제공해준다.

 
특성 중요도를 평가
특성을 하나씩 랜덤하게 섞어서 모델 성능의 변화를 관찰
반복하여 얻은 특성의 중요도(importances), 평균(importances_mean), 표준편차(importances_std)를 담고 있다.
In [17]:
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) 
# n_repeats기본(랜덤하게 섞을 횟수)은 5
print(result.importances_mean) 
 
[0.08876275 0.23438522 0.08027708]
In [12]:
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     ]
In [18]:
hgb.score(test_input, test_target)
Out[18]:
0.8723076923076923
 

XGBoost (오픈소스)

tree_method='hist' : 히스토그램 기반 그레이디언트 부스팅 라이브러리
In [21]:
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 (오픈소스)

히스토그램 기반 그레이디언트 부스팅 라이브러리
In [22]:
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

출처 : 박해선, 『혼자공부하는머신러닝+딥러닝』, 한빛미디어(2021), p263-280

Comments