Ensemble
지난 포스팅에서 Ensemble의 정의에 대하여 설명하였지만 다시한번 말하고 가면 이해에 도움이 될까 싶어 간단히 말하고 넘어가겠다.
Ensemble의 종류로는 투표방식과 Boosting방식이 있는데 이중 투표방식에는 Bagging과 Voting이 있다.
Bagging은 같은 유형의 알고리즘들을 조합하되 각각 학습하는 데이터는 다르게 하였다.
반면
이번에 할 Voting은 서로다른 종류의 알고리즘들을 결합한것이다.
Ensemble - Boosting Model
Boosting
Boosting의 종류에는 Boosting에서 사용할 수 있는 모델 중 하나로 GradientBoosting 모델이 있다.
GradientBoosting
학습 후 새로운 데이터 예측
주요 파라미터
<예제를 통해 살펴보자!>
from dataset import get_breast_cancer_dataset
(X_train, X_test, y_train, y_test), feature_names = get_breast_cancer_dataset()
X_train.shape, X_test.shape
((426, 30), (143, 30))
from sklearn.ensemble import GradientBoostingClassifier # 앙상블- 분류 -> 추론해나가자
gbc = GradientBoostingClassifier(random_state=0)
gbc.fit(X_train, y_train)
pred_train = gbc.predict(X_train)
pred_test = gbc.predict(X_test)
proba_train = gbc.predict_proba(X_train) # 확률로 추론했다.
proba_test = gbc.predict_proba(X_test)
from metrics import print_metrics_classification
print_metrics_classification(y_train, pred_train, proba_train[:, 1], "Trainset")
print_metrics_classification(y_test, pred_test, proba_test[:, 1], "Testset")
import pandas as pd
fi = pd.Series(gbc.feature_importances_, index=feature_names)
fi.sort_values(ascending=False)
learning rate 변화에 따른 성능변화
import time
max_depth = 1
n_estimators = 10000
lr = 0.0001
# lr = 0.01
# lr = 0.1
gbc2 = GradientBoostingClassifier(n_estimators=n_estimators,
learning_rate=lr,
max_depth=max_depth,
random_state=0)
s = time.time()
gbc2.fit(X_train, y_train)
e = time.time()
pred_train2 = gbc2.predict(X_train)
pred_test2 = gbc2.predict(X_test)
print(f"lr: {lr}, n_estimator: {n_estimators}, 학습시간:{e-s}초")
print_metrics_classification(y_train, pred_train2, title="Trainset")
print_metrics_classification(y_test, pred_test2, title="Test set")
GradientBoosting기반으로 Gradient Boost의 단점인 느린수행시간을 해결하고 과적합을 제어할 수 있는 규제들을 제공하여 성능을 높여 분산환경에서도 실행할 수 있도록 구현 나온 모델로 XGBoost(Extra Gradient Boost)가 있다.
XGBoost (Extream Gradient Boost)
XGBoost을 사용한 두가지 개발 방법
둘중 래퍼 XGBoost에 대하여 살펴보겠다.
<예제로 살펴보자!>
from xgboost import XGBClassifier, XGBRegressor
xgb = XGBClassifier(n_estimators=1000, learning_rate=0.01, max_depth=1, random_state=0)
xgb.fit(X_train, y_train)
feature importance
fi = pd.Series(xgb.feature_importances_, index=feature_names)
fi.sort_values(ascending=False
print_metrics_classification(y_train, xgb.predict(X_train), title="train set")
print_metrics_classification(y_test, xgb.predict(X_test), title="test set")
# 회귀
from dataset import get_boston_dataset
X_train, X_test, y_train, y_test = get_boston_dataset()
xgb_reg = XGBRegressor(n_estimators=1000, learning_rate=0.01,
max_depth=2, random_state=0)
xgb_reg.fit(X_train, y_train)
fi = pd.Series(xgb_reg.feature_importances_, index=X_train.columns)
fi.sort_values(ascending=False)
from metrics import print_metrics_regression
# 평가
print_metrics_regression(y_train, xgb_reg.predict(X_train), title="train set")
print_metrics_regression(y_test, xgb_reg.predict(X_test), title="test set")
Ensemble - Voting 방식
Voting의 유형(분류)
비슷한 성능을 내면서 서로 다른 예측하는 것이 많은 모델들을 묶어줄 때 성능이 올라간다.
hard voting
soft voting → 더 성능이 좋다.
VotingClassifier 클래스 이용
<예제로 살펴보자!>
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
from xgboost import XGBClassifier
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from dataset import get_breast_cancer_dataset
from metrics import print_metrics_classification
(X_train, X_test, y_train, y_test), feature_names = get_breast_cancer_dataset()
# 각 모델의 Hyper parameter는 최적의 성능을 내도록 튜닝한 값들 이라는 가정.
# Voting 앙상블 모델에 추가하는 모델들은 가장 좋은 성능을 내는 Hyper parameter를 가진
# (튜닝이기 끝난) 모델을 사용한다.
knn = Pipeline(steps=[('scaler', StandardScaler()),
('knn', KNeighborsClassifier(n_neighbors=5))])
svm = Pipeline(steps=[("scaler", StandardScaler()),
("svm", SVC(random_state=0, probability=True))])
rfc = RandomForestClassifier(n_estimators=200, max_depth=3, random_state=0)
xgb = XGBClassifier(n_estimators=500, learning_rate=0.01, max_depth=1, random_state=0)
model_list = [
("knn", knn),
("svm", svm),
("RandomForest", rfc),
("XGBoost", xgb)
]
# 모델이 test set에 대해 **추정한 결과를** 저장할 변수.
# 즉, 모델이 추정한 결과를 저장할 변수
test_predict_dict = {} # key: 모델이름, value: test set에 대한 추정한 label값.
for name, model in model_list:
model.fit(X_train, y_train)
pred_train = model.predict(X_train)
pred_test = model.predict(X_test)
test_predict_dict[name] = pred_test # test set 추정결과를 dic에 추가.
print_metrics_classification(y_train, pred_train, title=f"{name}-Train set")
print_metrics_classification(y_test, pred_test, title=f"{name}-Test set")
print()
# test set 기준 SVM이 성능이 제일 좋은 것을 알 수 있다.
각각의 모델들끼리 추론한 값들끼리의 상관관계를 보자.
# 테스트 결과가 있는 딕셔너리를 데이터프레임화한다.
import pandas as pd
df = pd.DataFrame(test_predict_dict)
df.head()
df.corr()
# Ordered Dictionary 형태로 묶어준다.
estimators = [
("svm", svm),
("knn", knn),
("random forest", rfc)
]
# hard voting # voting 방식 생략 시 hard voting하겠다는 것.
voting = VotingClassifier(estimators=estimators)
voting.fit(X_train, y_train)
print_metrics_classification(y_test, voting.predict(X_test), title='test set')
# 결과를 보면 성능이 올라가지않고 더 떨어진것을 볼 수 있다.
# soft voting- 확률로
voting = VotingClassifier(estimators=estimators, voting="soft")
voting.fit(X_train, y_train)
print_metrics_classification(y_test, voting.predict(X_test), title='test set')
# hard보다 성능이 좋게 나온다.
svm.predict_proba(X_test[:5])
knn.predict_proba(X_test[:5])
rfc.predict_proba(X_test[:5])
<voting하기 좋은 모델>
즉, Voting방식(다수결 투표방식)의 앙상블은 각각 좋은 성능을 내지만 다른 예측을 하는 다양한 모델을 모아서 하는 것이 좋다. 대부분의 모델들이 동일한 예측을 만든다면 새로운 모델을 추가해 얻는 이득이 적기 때문이다.
다양하게 ex)
<예제로 살펴보자!>
from dataset import get_boston_dataset
X_train, X_test, y_train, y_test = get_boston_dataset()
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.neighbors import KNeighborsRegressor
from sklearn.ensemble import VotingRegressor
from sklearn.pipeline import make_pipeline
lr = make_pipeline(StandardScaler(), LinearRegression()) # make_pipeline : 이름을 생략할 수 있다. 알아서 클래스의 이름을 따서 만듬.
rfr = RandomForestRegressor(max_depth=3, random_state=0)
knn = make_pipeline(StandardScaler(), KNeighborsRegressor(n_neighbors=5))
from metrics import print_metrics_regression
model_list = [
('Linear Regression', lr),
('Random Forest', rfr),
('KNN', knn)
]
for name, model in model_list:
model.fit(X_train, y_train)
pred_train = model.predict(X_train)
pred_test = model.predict(X_test)
print_metrics_regression(y_train, pred_train, f"{name} - trainset")
print_metrics_regression(y_test, pred_test, f"{name} - testset")
print()
# Random Forest의 오차가 가장 적은 것을 알 수 있다.
voting_reg = VotingRegressor(estimators=model_list)
# 재학습
voting_reg.fit(X_train, y_train)
print_metrics_regression(y_test, voting_reg.predict(X_test))