05-1 결정 트리¶
로지스틱 회귀로 와인 분류하기¶
# 데이터 준비
import pandas as pd
wine = pd.read_csv('https://bit.ly/wine_csv_data')
wine.head() # class가 0이면 레드 와인, 1이면 화이트 와인
alcohol | sugar | pH | class | |
---|---|---|---|---|
0 | 9.4 | 1.9 | 3.51 | 0.0 |
1 | 9.8 | 2.6 | 3.20 | 0.0 |
2 | 9.8 | 2.3 | 3.26 | 0.0 |
3 | 9.8 | 1.9 | 3.16 | 0.0 |
4 | 9.4 | 1.9 | 3.51 | 0.0 |
# 데이터 분류
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['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.preprocessing import StandardScaler
ss = StandardScaler()
ss.fit(train_input)
train_scaled = ss.transform(train_input)
test_scaled = ss.transform(test_input)
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
lr.fit(train_scaled, train_target)
print(lr.score(train_scaled, train_target))
print(lr.score(test_scaled, test_target))
0.7808350971714451
0.7776923076923077
print(lr.coef_, lr.intercept_)
[[ 0.51270274 1.6733911 -0.68767781]] [1.81777902]
☆ 로지스틱 회귀는 학습의 결과를 설명하기 어렵다.(단점)
결정 트리¶
# 결정 트리 구현 코드
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(train_scaled, train_target)
print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))
# 과대적합이다!!
0.996921300750433
0.8592307692307692
# 가지치기 : 과대적합 문제를 해결하고자 실행
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_scaled, train_target)
print(dt.score(train_scaled, train_target))
print(dt.score(test_scaled, test_target))
0.8454877814123533
0.8415384615384616
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH']) # filled=True 강도에 따른 색깔 변화
plt.show()
# 표준화 작업한 scaled 변수를 사용하지 않았다.
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(train_input, train_target)
print(dt.score(train_input, train_target))
print(dt.score(test_input, test_target))
# 동일한 결과 도출
0.8454877814123533
0.8415384615384616
# 표준화가 되어있지 않아 더 직관적 해석이 가능
plt.figure(figsize=(20,15))
plot_tree(dt, filled=True, feature_names=['alcohol', 'sugar', 'pH'])
plt.show()
# 변수별 중요도
print(dt.feature_importances_)
[0.12345626 0.86862934 0.0079144 ]
- 특성 중요도는 각 노드의 정보 이득과 전체 샘플에 대한 비율을 곱한 후 특성별로 더하여 계산
- 불순도는 결정 트리가 최적의 질문을 찾기 위한 기준으로 사이킷런은 지니 불순도와 엔트로피 불순도를 제공한다.
05-2 교차 검증과 그리드 서치¶
☆ 검증 세트 : 하이퍼파라미터 튜닝을 위해 모델을 평가할 때, 테스트 세트를 사용하지 않기 위해 훈련 세트에서 다시 떼어 낸 데이터 세트
# 데이터 준비
wine = pd.read_csv('https://bit.ly/wine_csv_data')
data = wine[['alcohol', 'sugar', 'pH']].to_numpy()
target = wine['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)
# 검증 세트 만들기
sub_input, val_input, sub_target, val_target = train_test_split(
train_input, train_target, test_size=0.2, random_state=42)
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(random_state=42)
dt.fit(sub_input, sub_target)
print(dt.score(sub_input, sub_target))
print(dt.score(val_input, val_target))
0.9971133028626413
0.864423076923077
☆ 교차 검증 : 훈련 세트를 여러 폴드로 나눈 다음 한 폴드가 검증 세트의 역할을 하고 나머지 포드에서는 모델을 훈련함
from sklearn.model_selection import cross_validate # 기본값 5-폴드 교차 검증
# 교차 검증은 따로 섞지 않는다.
scores = cross_validate(dt, train_input, train_target)
print(scores)
{'fit_time': array([0.01097155, 0.0099721 , 0.00897694, 0.00996828, 0.00997376]), 'score_time': array([0.0009973 , 0.00100183, 0. , 0.00099826, 0.00199556]), 'test_score': array([0.86923077, 0.84615385, 0.87680462, 0.84889317, 0.83541867])}
# 교차 검증의 평균 점수는
import numpy as np
print(np.mean(scores['test_score']))
0.855300214703487
# 10-폴드 교차 검증
# splitter를 통해 지정하면 섞기 가능
from sklearn.model_selection import StratifiedKFold
splitter = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
scores = cross_validate(dt, train_input, train_target, cv=splitter)
print(np.mean(scores['test_score']))
0.8574181117533719
하이퍼파라미터 튜닝¶
☆ 그리드 서치 : 하이퍼파라미터 탐색을 자동화해 주는 도구, 탐색과 교차 검증을 한 번에 수행
# 그리드 서치
import numpy as np
from sklearn.model_selection import GridSearchCV
# 3개의 최적의 값 탐색
params = {'min_impurity_decrease': np.arange(0.0001, 0.001, 0.0001),
'max_depth':np.arange(5, 20, 1),
'min_samples_split':np.arange(2, 100, 10)
}
gs = GridSearchCV(DecisionTreeClassifier(random_state=42), params)
gs.fit(train_input, train_target)
GridSearchCV(estimator=DecisionTreeClassifier(random_state=42),
param_grid={'max_depth': array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
'min_impurity_decrease': array([0.0001, 0.0002, 0.0003, 0.0004, 0.0005, 0.0006, 0.0007, 0.0008,
0.0009]),
'min_samples_split': array([ 2, 12, 22, 32, 42, 52, 62, 72, 82, 92])})
# 최상의 매개변수 조합 출력
print(gs.best_params_)
{'max_depth': 14, 'min_impurity_decrease': 0.0004, 'min_samples_split': 12}
# 최고 교차 검증 점수
print(np.max(gs.cv_results_['mean_test_score']))
0.8683865773302731
랜덤 서치 : 연속적인 매개별수 값을 탐색할 때 유용
랜덤 서치에는 매개변수 값의 목록을 전달하는 것이 아니라 매개변수를 샘플링할 수 있는 확률 분포 객체를 전달
# 랜덤 서치
from scipy.stats import uniform, randint
params = {'min_impurity_decrease': uniform(0.0001, 0.001),
'max_depth': randint(20, 50),
'min_samples_split': randint(2, 25),
'min_samples_leaf': randint(1, 25),
}
from sklearn.model_selection import RandomizedSearchCV
gs = RandomizedSearchCV(DecisionTreeClassifier(random_state=42), params,
n_iter=100, random_state=42)
# n_iter=100 매개변수 범위에서 총 100번을 샘플링하여 교차 검증을 수행
gs.fit(train_input, train_target)
RandomizedSearchCV(estimator=DecisionTreeClassifier(random_state=42),
n_iter=100,
param_distributions={'max_depth': <scipy.stats._distn_infrastructure.rv_frozen object at 0x0000027C8305F580>,
'min_impurity_decrease': <scipy.stats._distn_infrastructure.rv_frozen object at 0x0000027C8305F970>,
'min_samples_leaf': <scipy.stats._distn_infrastructure.rv_frozen object at 0x0000027C8305F1C0>,
'min_samples_split': <scipy.stats._distn_infrastructure.rv_frozen object at 0x0000027C8305F3A0>},
random_state=42)
# 최적의 매개변수 조합 출력
print(gs.best_params_)
{'max_depth': 39, 'min_impurity_decrease': 0.00034102546602601173, 'min_samples_leaf': 7, 'min_samples_split': 13}
# 최고 교차 검증 점수
print(np.max(gs.cv_results_['mean_test_score']))
0.8695428296438884
05-3 트리의 앙상블¶
☆ 랜덤 포레스트 : 대표적인 결정 트리 기반의 앙상블 학습 방법, 부트스트랩 샘플을 사용하고 랜덤하게 일부 특성을 선택하여 트리를 만드는 것이 특징
☆ 부트스트랩 샘플 : 데이터 세트에서 중복을 허용하여 데이터를 샘플링하는 방식
# 랜덤 포레스트
# 랜덤하게 샘플 선택하여 과대적합되는 것을 막아준다
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(random_state=42) # n_jobs=-1 : 모든 cpu 코어 사용
scores = cross_validate(rf, train_input, train_target, return_train_score=True) # n_jobs=-1 : 병렬로 교차 검증 수행
# return_train_score=True : 검증 점수와 훈련 세트에 대한 점수도 반환
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# 과대적합된 결과 도출
0.9973541965122431 0.8905151032797809
# 변수 중요도
rf.fit(train_input, train_target)
print(rf.feature_importances_)
# 특성의 일부를 랜덤하게 선택하여 훈련하기 때문에 랜덤 포레스트는 INDEX1의 값이 낮아진 것을 확인할 수 있다.
[0.23167441 0.50039841 0.26792718]
# 부트스트랩 샘플에 포함되지 않은 샘플 OOB를 사용하여 결정 트리 평가
rf = RandomForestClassifier(oob_score=True, n_jobs=-1, random_state=42)
rf.fit(train_input, train_target)
print(rf.oob_score_)
0.8934000384837406
엑스트라 트리¶
☆ 엑스트라 트리는 부트스트랩 샘플을 사용하지 않는다.
☆ 결정 트리를 만들 때 전체 훈련 세트 사용
☆ 노드 분할할 때 가장 좋은 분할을 찾는 것이 아니라 무작위 분할 (그렇기에 속도가 빠르며 과대적합을 감소 시킴)
from sklearn.ensemble import ExtraTreesClassifier
et = ExtraTreesClassifier(random_state=42)
scores = cross_validate(et, train_input, train_target, return_train_score=True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
0.9974503966084433 0.8887848893166506
# 변수 중요도
et.fit(train_input, train_target)
print(et.feature_importances_)
[0.20183568 0.52242907 0.27573525]
그레이디언트 부스팅¶
그레이디언트 부스팅 : 깊이가 얕은 결정 트리를 사용하여 이전 트리의 오차를 보완하는 방식으로 앙상블 하는 방법, 깉이가 얕은 결정 트리 사용하기 때문에 높은 일반화 성능
# 그레이디언트 부스팅
from sklearn.ensemble import GradientBoostingClassifier
gb = GradientBoostingClassifier(random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# 과대적합이 거의 나타나지않는다.
# 학습률을 증가시키고 트리의 개수를 늘리면 성능 향상될 것이다.
0.8881086892152563 0.8720430147331015
# 트리 5배 증가, 학습률 기본 0.1에서 0.2 증가
gb = GradientBoostingClassifier(n_estimators=500, learning_rate=0.2, random_state=42)
scores = cross_validate(gb, train_input, train_target, return_train_score=True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
# 더 좋은 값이 나온다
0.9464595437171814 0.8780082549788999
# 변수 중요도
gb.fit(train_input, train_target)
print(gb.feature_importances_)
[0.15872278 0.68010884 0.16116839]
일반적으로 그레이디언트 부스팅이 랜덤 포레스트보다 조금 더 높은 성능을 얻을 수 있다.
하지만 순서대로 트리를 추가하기 때문에 훈련 속도가 느리다.
히스토그램 기반 그레이디언트 부스팅¶
☆ 그레이디언트 부스팅은 그레이디언트 부스팅의 속도를 개선한 것으로 과대적합을 잘 억제하며 더 높은 성능 제공
☆ 그레이디언트 부스팅은 입력 특성을 256개의 구간으로 나누어 노드를 분할할 때 최적의 분할을 매우 빠르게 찾을 수 있다.
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)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
0.9321723946453317 0.8801241948619236
# 변수 중요도
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,)
print(result.importances_mean)
[0.08876275 0.23438522 0.08027708]
result = permutation_importance(hgb, test_input, test_target, n_repeats=10,
random_state=42)
print(result.importances_mean)
[0.05969231 0.20238462 0.049 ]
hgb.score(test_input, test_target)
0.8723076923076923
XGBoost¶
XGBoost는 히스토그램 기반 Gradient Boosting 알고리즘을 분산환경에서도 실행할 수 있도록 구현해놓은 라이브러리이다.
약한 예측 모형들의 학습 에러에 가중치를 두고, 순차적으로 다음 학습 모델에 반영하여 강한 예측 모델을 만드는 것이다.
장점 : 분류와 회귀영역에서 뛰어난 예측 성능 발휘, 과적합 규제(Regularization), GBM(gradient boostin algorithm) 대비 빠른 수행시간
pip install xgboost
Requirement already satisfied: xgboost in c:\work\envs\datascience\lib\site-packages (1.4.2)
Requirement already satisfied: scipy in c:\work\envs\datascience\lib\site-packages (from xgboost) (1.6.2)
Requirement already satisfied: numpy in c:\work\envs\datascience\lib\site-packages (from xgboost) (1.20.1)
Note: you may need to restart the kernel to use updated packages.
pip install lightgbm
Requirement already satisfied: lightgbm in c:\work\envs\datascience\lib\site-packages (3.2.1)
Requirement already satisfied: scikit-learn!=0.22.0 in c:\work\envs\datascience\lib\site-packages (from lightgbm) (0.24.1)
Requirement already satisfied: wheel in c:\work\envs\datascience\lib\site-packages (from lightgbm) (0.36.2)
Requirement already satisfied: scipy in c:\work\envs\datascience\lib\site-packages (from lightgbm) (1.6.2)
Requirement already satisfied: numpy in c:\work\envs\datascience\lib\site-packages (from lightgbm) (1.20.1)
Requirement already satisfied: threadpoolctl>=2.0.0 in c:\work\envs\datascience\lib\site-packages (from scikit-learn!=0.22.0->lightgbm) (2.1.0)
Requirement already satisfied: joblib>=0.11 in c:\work\envs\datascience\lib\site-packages (from scikit-learn!=0.22.0->lightgbm) (1.0.1)
Note: you may need to restart the kernel to use updated packages.
from xgboost import XGBClassifier
xgb = XGBClassifier(tree_method='hist', random_state=42)
scores = cross_validate(xgb, train_input, train_target, return_train_score=True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
C:\work\envs\datascience\lib\site-packages\xgboost\sklearn.py:1146: UserWarning: The use of label encoder in XGBClassifier is deprecated and will be removed in a future release. To remove this warning, do the following: 1) Pass option use_label_encoder=False when constructing XGBClassifier object; and 2) Encode your labels (y) as integers starting with 0, i.e. 0, 1, 2, ..., [num_class - 1].
warnings.warn(label_encoder_deprecation_msg, UserWarning)
[21:17:46] WARNING: C:/Users/Administrator/workspace/xgboost-win64_release_1.4.0/src/learner.cc:1095: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'binary:logistic' was changed from 'error' to 'logloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
C:\work\envs\datascience\lib\site-packages\xgboost\sklearn.py:1146: UserWarning: The use of label encoder in XGBClassifier is deprecated and will be removed in a future release. To remove this warning, do the following: 1) Pass option use_label_encoder=False when constructing XGBClassifier object; and 2) Encode your labels (y) as integers starting with 0, i.e. 0, 1, 2, ..., [num_class - 1].
warnings.warn(label_encoder_deprecation_msg, UserWarning)
[21:17:46] WARNING: C:/Users/Administrator/workspace/xgboost-win64_release_1.4.0/src/learner.cc:1095: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'binary:logistic' was changed from 'error' to 'logloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
C:\work\envs\datascience\lib\site-packages\xgboost\sklearn.py:1146: UserWarning: The use of label encoder in XGBClassifier is deprecated and will be removed in a future release. To remove this warning, do the following: 1) Pass option use_label_encoder=False when constructing XGBClassifier object; and 2) Encode your labels (y) as integers starting with 0, i.e. 0, 1, 2, ..., [num_class - 1].
warnings.warn(label_encoder_deprecation_msg, UserWarning)
[21:17:46] WARNING: C:/Users/Administrator/workspace/xgboost-win64_release_1.4.0/src/learner.cc:1095: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'binary:logistic' was changed from 'error' to 'logloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
C:\work\envs\datascience\lib\site-packages\xgboost\sklearn.py:1146: UserWarning: The use of label encoder in XGBClassifier is deprecated and will be removed in a future release. To remove this warning, do the following: 1) Pass option use_label_encoder=False when constructing XGBClassifier object; and 2) Encode your labels (y) as integers starting with 0, i.e. 0, 1, 2, ..., [num_class - 1].
warnings.warn(label_encoder_deprecation_msg, UserWarning)
[21:17:46] WARNING: C:/Users/Administrator/workspace/xgboost-win64_release_1.4.0/src/learner.cc:1095: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'binary:logistic' was changed from 'error' to 'logloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
C:\work\envs\datascience\lib\site-packages\xgboost\sklearn.py:1146: UserWarning: The use of label encoder in XGBClassifier is deprecated and will be removed in a future release. To remove this warning, do the following: 1) Pass option use_label_encoder=False when constructing XGBClassifier object; and 2) Encode your labels (y) as integers starting with 0, i.e. 0, 1, 2, ..., [num_class - 1].
warnings.warn(label_encoder_deprecation_msg, UserWarning)
[21:17:47] WARNING: C:/Users/Administrator/workspace/xgboost-win64_release_1.4.0/src/learner.cc:1095: Starting in XGBoost 1.3.0, the default evaluation metric used with the objective 'binary:logistic' was changed from 'error' to 'logloss'. Explicitly set eval_metric if you'd like to restore the old behavior.
0.9555033709953124 0.8799326275264677
# LightGBM
from lightgbm import LGBMClassifier
lgb = LGBMClassifier(random_state=42)
scores = cross_validate(lgb, train_input, train_target, return_train_score=True)
print(np.mean(scores['train_score']), np.mean(scores['test_score']))
0.935828414851749 0.8801251203079884
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:80% !important;}</style>"))
'Book report > 혼자 공부하는 머신러닝 + 딥러닝' 카테고리의 다른 글
[혼자 공부하는 머신러닝 + 딥러닝] Chapter 7 딥러닝을 시작합니다 (0) | 2021.09.04 |
---|---|
[혼자 공부하는 머신러닝 + 딥러닝] Chapter 6 비지도 학습 (0) | 2021.09.03 |
[혼자 공부하는 머신러닝 + 딥러닝] Chapter 4 다양한 분류 알고리즘 (0) | 2021.08.31 |
[혼자 공부하는 머신러닝 + 딥러닝] Chapter 3 회귀 알고리즘과 모델 규제 (0) | 2021.08.31 |
[혼자 공부하는 머신러닝 + 딥러닝] Chapter 2 데이터 다루기 (0) | 2021.08.30 |