--16.앙상블 학습(트리).ipynb--
Random Forest


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
base_path = r'/content/drive/MyDrive/dataset'
file_path = os.path.join(base_path, 'wine.csv')
wine_df = pd.read_csv(file_path)
wine_df
wine_df.columns
data = wine_df[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine_df['class'].to_numpy()
from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = \
train_test_split(data, target, test_size = 0.2, random_state=42)
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_validate
rf = RandomForestClassifier(n_jobs=-1, random_state=42)
scores = cross_validate(rf, train_input, train_target, return_train_score=True, n_jobs=-1)
scores
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
"""
랜덤포레스트는 '결정트리의 앙상블'이기 때문에
DecisionTreeClassifier 가 제공하는 중요 매개변수를 모두 제공함.
=> criterion, max_depth, max_features, min_samples_split,
min_impurity_decrease, min_samples_leaf 등..
결정트리의 큰 장점중 하나 => '특성 중요도' 계산
랜덤포레스트의 특성중요도는 각각의 결정트리의 특성중요도를 취합한 결과.
"""
None
rf.fit(traininput, train_target)
rf.feature_importances
"""
알코올 , 당도 , ph
[0.12345626, 0.86862934, 0.0079144 ] <= 지난 단원의 특성 중요도
[0.23167441, 0.50039841, 0.26792718] <= 이번 랜덤포레스트의 특성 중요도
이전에 비해 당도의 중요도가 감소하고, 알코올과 pH의 중요도가 상승했다.
왜?
랜덤포레스트는 '특성의 일부'를 '랜덤하게 선택'하여 결정트리를 훈련하기 때문!
그 결과! 하나의 특성에 과도하게 집중되지 않고, 좀 더 많은 특성이 훈련에 기여할 확률이 높아진다.
=> 과대적합을 줄이고, '일반화' 성능을 높이는데 도움이 된다.
"""
None
"""
RandomForestClassifier는 자체적으로 모델 평가 하는 기능이 있다.
부트스트랩샘플 만들 때 포함되지 않은 샘플들 (이를 OOB)
OOB를 활용하여 결정트리를 평가함.
"""
None
rf = RandomForestClassifier(
oob_score=True, # OOB 활용!
n_jobs=-1, random_state=42)
rf.fit(traininput, train_target)
print(rf.oob_score)
Extra Tree
"""
랜덤포레스트와 매우 비슷하게 동작!!
차이점! 부트스트랩 샘플을 사용하지 않는다!
=> 결정트리 만들때 '전체훈련세트' 를 사용함!
=> 대신! 노드를 분할할 때 가장 좋은 분할을 찾는 것이 아니라 무작위로 분할!
결정트리에서 이런식으로 특성을 무작위로 분할하면 성능이 낮아진다!!
그러나 많은 트리를 앙상블 하기 때문에 과대적합을 막고 검증세트 점수를 높이는 효과가 있다.
"""
None
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)
scores
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
et.fit(traininput, train_target)
print(et.feature_importances)
Gradient Boosting
"""
그레디언트 부스팅은 깊이가 얕은 결정 트리를 사용하여 트리의 오차를 보완하는 방식으로 앙상블 하는 방법
GradientBoostingClassifier 는 기본적으로 깊이가 3인 결정트리를 100개 사용.
깊이가 얕은 트리를 사용하기 때문에 과대적합에는 강하고, 높은 일반화 성능 기대함.
"""
None
"""
'경사하강법'을 사용함.
'분류' 에서는 로지스틱손실 함수 사용.
'회귀' 에서는 평균제곱오차 함수 사용.
'그레디언트 부스팅'은 결정트리를 계속 추가하면서 가장 낮은곳을 찾아 이동합니다.
손실 함수의 낮은곳으로 '천천히 조금씩' 이동하기 위해 얕은 트리를 사용하는것.
"""
None
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']))
"""
0.9974503966084433 0.8887848893166506 <- Extra Tree
0.8881086892152563 0.8720430147331015 <- Gradient Boosting
거의 과대적합이 억제되고 있다.
"""
None
gb = GradientBoostingClassifier(
n_estimators = 500, # 트리의 개수를 늘려보자
learning_rate = 0.2, # 학습률 증가 (디폴트 0.1)
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.9974503966084433 0.8887848893166506 <- Extra Tree
0.8881086892152563 0.8720430147331015 <- Gradient Boosting
0.9464595437171814 0.8780082549788999 <- Gradient Boosting(파라미터 조정)
"""
None
gb.fit(train_input, train_target)
gb.featureimportances # 특성 중요도
"""
알코올 당도 pH
0.23167441, 0.50039841, 0.26792718 <= Random Forest
0.20183568 0.52242907 0.27573525 <= Extra Tree
0.15872278, 0.68010884, 0.16116839 <= Gradient Boosting (파라미터)
"""
None
Histogram-based Gredient Boosting
"""
입력데이터의 특성을 '구간'으로 나눈다. (기본 256개의 구간)
=> 노드를 분할할때 최적의 분할을 매우 빠르게 찾을 수 있다.
256개의 구간중에서 하나는 떼어놓는다. => 누락된 값을 위해 사용하기 위함.
"""
None
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']))
"""
0.8881086892152563 0.8720430147331015 <- Gradient Boosting
0.9321723946453317 0.8801241948619236 <- HistGradientBoosting
"""
None
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)
result.importances_mean
"""
알코올 당도 pH
0.23167441, 0.50039841, 0.26792718 <= Random Forest
0.20183568, 0.52242907, 0.27573525 <= Extra Tree
0.15872278, 0.68010884, 0.16116839 <= Gradient Boosting (파라미터)
0.08876275, 0.23438522, 0.08027708 <= HistGradientBoosting
"""
None
result = permutation_importance(hgb, test_input, test_target, n_repeats=10, random_state=42, n_jobs=-1)
result.importances_mean
hgb.score(test_input, test_target)
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']))
"""
마이크로소프트에서 만든 히스토그램 기반 그레디언트 부스팅 라이브러리
"""
None
from lightgbm import LGBMClassifier
lgb = LGBMClassifier(tree_method='hist', 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']))