물먹는산세베리아

[혼공머신] 05-3. 트리의 앙상블 본문

AI/Machine Learning & Deep Learning

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

suntall 2022. 8. 4. 10:57

정형 데이터와 비정형 데이터

정형데이터

- 어떤 구조로 되어 있다

- CSV, Excel에 저장하기 쉬움

 

랜덤 포레스트

'랜덤'으로 선택된 샘플, 특성 사용 → 훈련 세트 과대적합 막음(기본 매개변수 설정만으로도 좋은 결과를 내기도 함)

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

cross_valideate() 교차검증

n_jobs: -1로 지정

- RandomForestClassifier는 기본적으로 100개의 결정 트리를 사용하기 때문에 모든 CPU 코어 사용 권장

- 병렬로 교차검증

return_train_score: True

- 검증 점수, 훈련 세트 점수 함께 반환 (비교 시 과대적합 파악 용이)

훈련세트에 과대적합

 

특성중요도 계산

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

각 결정 트리의 특성 중요도를 취합한 것임

앞에서 만든 '1절 결정 트리'의 특성 중요도와 차이 발생 이유 → 특서으이 일부를 랜덤하게 선택하여 결정 트리를 훈련하기 때문

=> 하나의 특성에 과도한 집중 x, 과대적합 줄이고 일반화 성능 높임

 

 

자체 모델 평가

RandomForestClassifier의 기능

OOB(out of bag) 샘플: 훈련 세트에서 중복을 허용하여 부트 스트랩 샘플을 만들고 남는 샘플

OOB 샘플로 훈련한 결정 트리 평가 가능 '검증 세트' 역할

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

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

oob_score: True로 설정해야 함. 

각 결정 트리의 OOB 점수 평균 출력

교차 검증 대신 가능! (훈련 세트에 더 많은 샘플 사용 가능)

 

 

엑스트라 트리

랜덤 포레스트와의 공통점

- 100개의 결정 트리 훈련

- 결정 트리가 제공하는 대부분의 매개변수 지원

- 전체 특성 중 일부 특성을 랜덤 선택해 노트 분할에 사용

 

랜섬포레스트와의 차이점

- 부트스트랩 샘플 사용 X (결정 트리 만들 때 전체 훈련 세트 사용)

- 노드 분할 시 무작위 분할 (가장 좋은 분할 찾기 X)

- 결정 트리: splitter='random'

 

결정 트리에서 특성 무작위 분할 시

1) 성능은 낮아지나

2) 많은 트리를 앙상블 하기 때문에 과대 적합을 막고 검증 세트 점수를 높임

 

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 (사이킷런 제공 엑스트라 트리 회귀버전)

 

 

그레이디언트 부스팅

깊이가 얕은 결정 트리를 사요해 이전 트리의 오차 보완하는 방식으로 앙상블

 

GradientBoostingClaasifier(분류)

- 깊이가 3인 결정트리 3개 사용

- 깊이가 얕아 과대적합에 강함, 높은 일반화 성능 기대 가능

 

GradientBoostingRegressor(회귀)

 

경사하강법을 사용해 트리를 앙상블에 추가함

1) 분류 시, 로지스틱 손실 함수 사용

2) 회귀 시, 평균 제곱 오차 함수 사용

 

*경사하강법은 손실 함수를 '산'으로 정의해 가장 낮은 곳을 찾아 내려오는 과정임

*가장 낮은 곳을 찾는 방법: 모델의 가중치, 절편 조금씩 바꾸기

 

그레이디언트 부스팅은 결정 트리를 계속 추가하면서 가장 낮은 곳으로 이동함.

손실 함수의 낮은 곳으로 '천천히 조금씩' 이동해야 하기 때문에 깊이가 얕은 트리 사용, 학습률 매개변수로 속도 조절

 

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

과대적합되지 않음.

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

학습률 증가, 트리 개수 늘리면 성능 향상됨

결정 트리 개수 500개

learning_rate 0.2 (기본값 0.1)

 

특성중요도 계산

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

일부 특성(당도)에 집중됨.

 

 

subample: 1.0이면 전체 훈련 세트 사용, 1보다 작으면 훈련 세ㅡ 일부 사용

-> 경사 하강법 단계마다 일부 샘플을 랜덤하게 선택하여 진행하는 ㄴ확률적 경사하강법, 미니배치 경사하강법과 비슷

 

=> 근데 언제 쓰는 거야 어디다 쓰는 거지

 

랜덤 포레스트보다 조금 더 높은 성능을 얻을 수 있지만 트리 추가로 인해 훈련 속도가 느리다.

n_jobs 매개변수가 없음

 

 

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

그레이디언트 부스팅의 속도, 성능 개선한 것

- 입력 특성을 256 구간으로 나눔

- 따라서 노드 분할 시 최적의 분할을 매우 빠르게 찾을 수 있음

- 256 구간 중 하나는 떼어 놓고 누락된 값을 위해서 사용함 (입력에 누락된 특성 있어도 전처리 필요 X)

어떻게 사용한다는거지

 

HistGradientBoostingClassifier(분류)

max_Iter: 부스팅 반복 횟수 지정(트리 개수 지정)

 

HistGradientBoostingRegressor(회귀)

 

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

 

과대적합 잘 억제하고, 그레이디언트 부스팅보다 조금 더 성능이 높음

 

특성중요도 계산

1) 훈련세트

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() 함수 사용

특성을 하나씩 랜덤하게 섞어서 모델 성능 변화 관찰(어떤 특성이 중요한지)

훈련 세트, 테스트 세트, 사이킷런 제공 추정기 모델에도 사용

n_repeats: 랜덤하게 섞을 횟수

특성 중요도, 평균, 표준편차

 

2) 테스트세트

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)

87% 정도의 정확도

단일 결정 트리보다 좋은 결과를 얻음(랜덤 서치 테스트 정확도 86%)

 

※그레이디언트 부스팅 알고리즘 구현한 라이브러리

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

tree_method 값을 'hist'로 지정 시 히스토그램 기반 레이디언트 부스팅 사용 가능

 

LightGMB

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

MS 작품

인기쟁이