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

챕터 05 - 3

codehunter 2023. 7. 30. 13:19

이번 챕터는 약간 정리하는 과정이 있다.

 

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

데이터의 종류는 크게 정형데이터와 비정형데이터로 나뉘는데 정형데이터는 즉 어떤 구조화된 데이터라는 뜻인데 머신러닝 알고리즘은 정형데이터에 잘 맞는데 그중에 정형 데이터를 다르는데 가장 뛰어난 성과를 내는 알고리즘이 앙상블 학습이고 이 알고리즘은 결정 트리 기반으로 만들어져 있다.

 

그럼 비정형 데이터는 어떤 알고리즘을 사용해야 할까? 신경망 알고리즘이다.

 

이제 앙상블 알고리즘을 학습해보자

 

랜덤포레스트

앙상블 학습의 대표 주자 중 대표 주자 중 하나로 안정적인 성능 덕분에 널리 사용되고 있다.

사용법은 랜덤포레스트는 각 트리를 훈련하기 위한 데이터를 랜덤하게 만드는데 이 데이터를 만드는 방법이 특이하다. 우리가 입력한 훈련데이터에서 랜덤하게 샘플을 추출하여 훈련 데이터를 만든다. 이때 한 샘플이 중복되어 추출될 수도 있다.

이렇게 만들어진 샘플을 부트스트랩 샘플이라고 부른다. 기본적으로 부트스트랩 샘플은 훈련 세트의 크기와 같게 만든다. 

 

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

분류모델인 RandomForestClassifier는 기본적으로 전체 특성 개수의 제곱근만큼의 특성을 선택한다. 즉 4개의 특성이 있다면 노드마다 2개를 랜덤하게 선택하여 사용한다.

 

사이킷런의 랜덤 포레스트는 기본적으로 100개의 결정 트리를 이런 방식으로 훈련한다.

그럼 RandomForestClassifier 클래스를 화이트 와인을 분류하는 문제에 적용해보자. 데이터 입력 - 훈련/테스트 세트 분리 까지는 기본으로 수행하고 cross_validate 함수를 사용해 교차 검증을 수행해보자. 훈련 세트와 검증 세트의 점수를 비교하면 과대적합을 파악하는데 용이하다. 이번 챕터에서는 점수를 높이는 것보다는 각 앙상블 알고리즘을 어떻게 훈련하는지에만 초점을 맞춰보자.

 랜덤 포레스트는 결정 트리의 앙상블이기 때문에 DecisionTreeClassifier가 제공하는 중요한 매개 변수를 모두 제공한다. 또한 결정 트리의 큰 장점 중 하나인 특성 중요도를 계산한다. 랜덤 포레스트 모델을 훈련 세트에 훈련한 후 특성 중요도를 출력해 보자. RandomForestClassifier 는 또한 자체적으로 모델을 평가하는 점수를 얻을 수 있다. 그게 oob_score_라는 점수이다.

 

엑스트라 트리

랜덤 포레스트와 매우 비슷하게 동작하는데 차이점은 부트스트랩 샘플을 사용하지 않는다는 점이다. 즉 각 결정 트리를 만들 때 전체 훈련 세트를 사용한다. 대신 노드를 분할할 때 가장 좋은 분할을 찾는게 아니라 무작위로 분할한다. 사용법은 간단하게 사이킷런에서 제공하는 ExtraTreesClassifier 를 사용하면 된다. 이 모델의 교차 점수를 보자.

랜덤 포레스트와 비슷한 결과를 얻었다. 엑스트라 트리도 랜덤 포레스트와 마찬가지로 특성 중요도를 제공한다.

 

그레이디언트 부스팅

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

GradientBoostingClassifier는 기본적으로 깊이가 3인 결정 트리를 100개 사용한다.

경사 하강법을 사용하여 트리를 앙상블에 추가한다. 그레이디언트 부스팅은 결정 트리를 계속 추가하면서 가장 낮은 곳을 찾아 이동한다. 

GradientBoostingClassifier를 사용해 와인 데이터셋의 교차 검증 점수도 같이 보자.

거의 과대적합이 되지 않았다. 그레이디언트 부스팅은 결정 트리의 개수를 늘려도 과대적합에 매우 강하다.

결정 트리 개수를 500개로 5배나 늘렸지만 과대적합을 잘 억제하고 있다. 그레이디언트 부스팅도 특성 중요도를 제공한다.

 

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

 

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

그레이디언트 부스팅의 속도와 성능을 더욱 개선한 것이 히스토그램 기반 그레이디언트 부스팅이다.

히스토그램 기반 그레이디언트 부스팅은 먼저 입력 특성을 256개의 구간으로 나눈다. 따라서 노드를 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있다. 사이킷에서 사용하려면 HistGradientBoostingClassifier을 쓰면 되는데 일반적으로 기본 매개변수로도 안정적인 성능을 얻을수 있다.

과대 적합을 잘 억제하면서 그레이디언트 부스팅보다 조금 더 높은 성능을 제공한다. 히스토그램 기반 그레이디언트 부스팅도 훈련세트에서 특성 중요도를 계산할수 있다. 

 

아래는 사이킷런 외에 히스토그램 기반 그레이디언트 부스팅 알고리즘을 구현한 라이브러리이다. 사용법은 거의 비슷하므로 점수만 보고가자.

XGBoost

히스토그램 기반 그레이디언트 부스팅 기반의 부스팅 라이브러리

LightGBM

마이크로소프트에서 만든 히스토그램 기반 그레이디언트 부스팅 기반의 부스팅 라이브러리

앙상블로 학습을 하려면 먼저 랜덤 포레스트로 시작해서 기준을 잡고 최신 알고리즘을 써보는 것도 좋은 방법이 될거 같다.

이제 지도학습의 방식과 대표 알고리즘들을 거의 살펴봤다.

 

전체코드

# 트리의 앙상블

## 랜덤 포레스트



import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split

wine = pd.read_csv('http://bit.ly/wine-date')

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

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

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

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

## 엑스트라 트리

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

### 그레이디언트 부스팅

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

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

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

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

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

hgb.score(test_input, test_target)

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

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

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

챕터 06 - 2  (0) 2023.08.04
챕터 06 - 1  (0) 2023.07.31
챕터 05 - 2  (0) 2023.07.28
챕터 05 - 1  (0) 2023.07.24
챕터 04 - 2  (0) 2023.07.21