728x90
반응형
박 팀장이 Pupbani를 불렀다.
- "이사님이 베스트 머신러닝 알고리즘을 보고 하라 하시네요.."
- "랜덤 포레스트를 사용해봐!!"
Pupbani는 박 팀장이 말한 랜덤 포레스트를 한번 해보기로 했다.
정형 데이터(Structured data)
- 쉽게 말해 어떤 구조로 되어 있다는 뜻
- csv, 데이터베이스, 엑셀에 저장하기 좋다.
- 앙상블 학습(Ensemble Learning)
- 정형 데이터를 다루는 데 가장 뛰어난 성과를 내는 알고리즘이다.
- 랜덤 포레스트, 엑스트라 트리, 그레이디언트 부스팅 등
비정형 데이터(Unstructured data)
- 정형 데이터와 반대되는 데이터
- 책의 글, 텍스트 데이터, 디지털카메라로 찍은 사진, 핸드폰으로 듣는 디지털 음악 등
- 신경망 알고리즘에 사용한다.
랜덤 포레스트(Random Forest)
- 앙상블 학습의 대표 주자
- 결정 트리를 랜덤 하게 만들어 결정 트리(나무)의 숲을 만드는 것이다.
- 각 결정 트리의 예측을 사용해 최종 예측을 만든다.
데이터 준비
- 각 트리를 훈련하기 위한 데이터를 랜덤하게 만든다.
- 입력한 훈련 데이터에서 랜덤하게 샘플을 추출하여 훈련 데이터를 만든다.
- 한 샘플이 중복되어 추출될 수도 있다.
- 이렇게 만들어진 샘플을 부트스트랩 샘플(Bootstrap Sample)이라고 한다.
- 부트스트랩 샘플은 훈련 세트의 크기와 같게 만든다.
- 각 노드를 분할할 때 전체 특성 중에서 일부 특성을 무작위로 고른 다음 이 중에서 최선의 분할을 찾는다.
- 분류 모델인 RandomForestClassifier는 기본적으로 전체 특성 개수의 제곱근만큼 특성을 선택한다.
- 회귀 모델인 RandomForestRegression은 전체 특성을 사용한다.
- 사이킷런의 랜덤 포레스트는 기본적으로 100개의 결정 트리를 이런 방식으로 학습한다.
- 분류 : 각 트리의 클래스별 확률을 평균하여 가장 높은 확률을 가진 클래스를 예측으로 삼는다.
- 회귀 : 각 트리의 예측을 평균한다.
- 이제 데이터를 준비해보자
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
wine = pd.read_csv('https://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)
- 훈련 세트와 테스트 세트를 만든다.
학습 및 평가
- 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(f"훈련 세트 정확도: {np.mean(scores['train_score'])*100:.2f}%")
print(f"테스트 세트 정확도: {np.mean(scores['test_score'])*100:.2f}%")
- 훈련 세트에 대해 과대 적합되어 있다.
- 랜덤 포레스트는 앙상블이기 때문에 DecisionTreeClassifier가 제공하는 중요한 매개변수를 전부 제공한다.
- 랜덤 포레스트 모델의 특성 중요도를 출력해보겠다.
rf.fit(train_input, train_target)
fimpt = rf.feature_importances_.reshape(-1,3).round(4) * 100
feature = list(wine.columns)[0:3]
print(pd.DataFrame(fimpt,columns=feature))
- 이전에 결정 트리에의 특성 중요도와 비교해보자
- 두 번째 특성인 당도의 중요도가 감소하고 알코올 도수와 pH가 올라갔다.
- 이렇게 되는 이유는 랜덤 포레스트가 특성의 일부를 랜덤 하게 선택하여 결정 트리를 훈련하기 때문이다.
- 과대 적합을 줄이고 일반화 선능을 높이는 데 도움이 된다.
- RandomForestClassifier에는 자체적으로 모델을 평가하는 점수를 얻을 수 있다.
- 랜덤 포레스트를 훈련하는 데 사용되는 샘플을 부트스트랩 샘플이라고 한다.
- 훈련 세트에서 중복을 허용하여 뽑아 샘플을 만드는 것
- 이 부트스트랩 샘플에 포함되지 않고 남는 샘플을 OOB(Out Of Bag) 샘플이라고 하는데 이 샘플을 사용하여 부트스트랩으로 훈련한 결정 트리를 평가할 수 있다.
- oob_score 매개변수를 True로 해야 한다.(기본값 False)
- 랜덤 포레스트를 훈련하는 데 사용되는 샘플을 부트스트랩 샘플이라고 한다.
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)
rf.fit(train_input, train_target)
print(f"OOB 점수 : {rf.oob_score_ * 100:.2f}%")
- OOB를 사용하면 교차 검증을 대신할 수 있어 훈련 세트에 더 많은 샘플을 사용할 수 있다.
엑스트라 트리(Extra Trees)
- 랜덤 포레스트와 매우 비슷하게 동작한다.
- 기본적으로 100개의 결정 트리를 학습한다.
- 결정 트리가 제공하는 대부분의 매개변수를 지원한다.
- 전체 특성 중에 일부 특성을 랜덤 하게 선택하여 노드를 분할하는 데 사용한다.
- 부트스트랩을 사용하지 않는다.
- 각 결정 트리를 만들 때 전체 훈련 세트를 사용한다.
- 노드를 분할할 때 무작위 분할을 한다.
- splitter = 'random'인 결정 트리가 엑스트라 트리가 사용하는 결정 트리이다.
- 트리를 앙상블 하기 때문에 과대 적합을 막고 검증 세트의 점수를 높이는 효과가 있다.
- ExtraTreesClassifier 클래스를 사용한다. (회귀는 ExtraTreesRegressor)
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(f"훈련 세트 정확도: {np.mean(scores['train_score'])*100:.2f}%")
print(f"테스트 세트 정확도: {np.mean(scores['test_score'])*100:.2f}%")
- 랜덤 포레스트와 비슷한 결과를 얻었다.
- 하지만 노드를 랜덤 하게 분할하기 때문에 빠른 계산 속도를 가진다.
- 특성 중요도는 다음과 같다.
et.fit(train_input, train_target)
fimpt = et.feature_importances_.reshape(-1,3).round(4) * 100
feature = list(wine.columns)[0:3]
print(pd.DataFrame(fimpt,columns=feature))
- 결정 트리와 비교했을 때 당도의 의존성이 작다.
그레디언트 부스팅(Gradient Boosting)
- 깊이가 얕은 결정 트리를 사용하여 이전 트리의 오차를 보완하는 방식으로 앙상블을 하는 방법이다.
- 과대 적합에 강하고 일반적으로 높은 일반화 성능을 기대할 수 있다.
- 경사 하강법을 사용하여 트리를 앙상블에 추가한다.
- 분류 : 로지스틱 손실 함수
- 회귀 : 평균 제곱 오차 함수
- 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(f"훈련 세트 정확도: {np.mean(scores['train_score'])*100:.2f}%")
print(f"테스트 세트 정확도: {np.mean(scores['test_score'])*100:.2f}%")
- 거의 과대 적합되지 않았다.
- 결정 트리의 개수를 늘려도 과대 적합에 매우 강하다.
- 학습률을 증가시키고 트리의 개수를 늘리면 성능이 더 향상될 수 있다.
- 특성 중요도를 확인해 보겠다.
gb.fit(train_input, train_target)
fimpt = gb.feature_importances_.reshape(-1,3).round(4) * 100
feature = list(wine.columns)[0:3]
print(pd.DataFrame(fimpt,columns=feature))
- 랜덤 포레스트보다 일부 특성(당도)에 더 집중한다.
- 트리 훈련에 사용할 훈련 세트의 비율을 정하는 매개변수인 subsample이 있다.
- 기본값은 1.0으로 전체 세트를 사용하는 것을 의미한다.
- subsample이 1보다 작으면 훈련 세트의 일부를 사용한다.
- 마치 일부 샘플을 랜덤 하게 선택하여 진행하는 확률적 경사 하강법이나 미니 배치 경사 하강법과 비슷하다.
히스토그램 기반 그레디언트 부스팅(Histogram-based Gradient Boosting)
- 먼저 입력 특성을 256개의 구간으로 나눈다.
- 노드들 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있다.
- 256개의 구간 중 하나를 떼어 놓고 누락된 값을 위해서 사용한다.
- 입력에 누락된 특성이 있더라도 이를 따로 전 처리할 필요가 없다.
- HistGradientBoostingClassifier 클래스를 사용한다.
- n_estimators : 트리의 개수 제한
- max_iter : 부스팅 반복 횟수
- 2022.10.24일 기준으로 HistGradientBoostingClassifier의 위치가 sklearn.experimental에서 sklearn.ensemble로 옮겨졌다.
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(f"훈련 세트 정확도: {np.mean(scores['train_score'])*100:.2f}%")
print(f"테스트 세트 정확도: {np.mean(scores['test_score'])*100:.2f}%")
- 과대 적합을 잘 억제하면서 그레디언트 부스팅보다 조금 더 높은 성능을 제공한다.
- 특성 중요도를 확인해보자
- sklearn은 permutation_ importance() 함수를 제공한다.
- 특성을 하나씩 랜덤 하게 섞어 모델의 성능이 변화하는지를 관찰하고 어떤 특성이 중요한지를 계산한다.
- n_repeats 매개변수는 랜덤 하게 섞을 횟수를 지정한다.
- 다음의 3개를 sklearn bunch(사전과 유사한 구조)로 반환한다
- importances_mean : 특성 중요도 평균
- importances_std : 특성 중요도 표준편차
- importances : 특성 중요도
- sklearn은 permutation_ importance() 함수를 제공한다.
hgb.fit(train_input, train_target)
from sklearn.inspection import permutation_importance
result = permutation_importance(hgb, test_input, test_target,
n_repeats = 10, random_state=42, n_jobs=-1)
print(f"특성 중요도 평균 : {result.importances_mean}")
print(f"특성 중요도 표준편차 : {result.importances_std}")
print(f"특성 중요도 : {result.importances}")
- 결과를 보면 그레디언트 부스팅과 비슷하게 조금 더 당도에 집중하고 있다는 것을 알 수 있다.
- 이 모델의 최종 성능을 확인해보자
print(f"모델 최종 정확도: {hgb.score(test_input, test_target)*100:.2f}%")
- 단일 결정 트리보다는 앙상블 모델이 더 좋은 결과를 얻을 수 있다.
사이킷런 말고도 그레디언트 부스팅 알고리즘을 구현한 라이브러리가 있다.
XGBoost
- 다양한 부스팅 알고리즘을 지원한다.
- tree_method를 'hist'로 지정하면 히스토그램 기반 그레디언트 부스팅을 사용할 수 있다.
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(f"훈련 세트 정확도: {np.mean(scores['train_score'])*100:.2f}%")
print(f"테스트 세트 정확도: {np.mean(scores['test_score'])*100:.2f}%")
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(f"훈련 세트 정확도: {np.mean(scores['train_score'])*100:.2f}%")
print(f"테스트 세트 정확도: {np.mean(scores['test_score'])*100:.2f}%")
이제 이사님에게 보고 하면 되겠군요!!
728x90
반응형
'AI > 기계학습(Machine Learning)' 카테고리의 다른 글
[기계학습/ML]14. 비지도학습 - K-평균(K-Means) (1) | 2022.12.05 |
---|---|
[기계학습/ML]13. 비지도학습 - 군집(Clustering) (0) | 2022.12.05 |
[기계학습/ML]11. 검증 세트 - 교차 검증, 그리드 서치 (0) | 2022.10.24 |
[기계학습/ML]10. 트리알고리즘 - 결정트리 (0) | 2022.10.23 |
[기계학습/ML]9. 확률적 경사 하강법 - 손실 함수, 에포크 (0) | 2022.10.23 |