Ensemble learning

 

Ensemble
일련의 예측기로부터 예측을 수집하면 가장 좋은 한 가지 모델보다 더 좋은 예측을 얻을 수 있습니다.
일련의 예측기를 ensemble이라고 부르고, 이러한 방식으로 학습하는 것을 ensemble learning, ensemble learning algorithm을 ensemble method라고 부릅니다.

Remarks

본 포스팅은 Hands-On Machine Learning with Scikit-Learn & TensorFlow (Auérlien Géron, 박해선(역), 한빛미디어) 를 기반으로 작성되었습니다.


1. Voting classifiers

  • Hard voting
    각 분류기가 예측하는 class를 모아 가장 많이 선택된 class로 예측하는 방법
  • Soft voting
    각 분류기가 예측하는 class의 확률을 평균내어 가장 높은 확률의 class로 예측하는 방법으로,
    더 정확하지만 class 확률을 추정할 수 있는 경우(predict_proba())에만 사용이 가능합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score


log_clf = LogisticRegression(solver="liblinear", random_state=42)
rnd_clf = RandomForestClassifier(n_estimators=10, random_state=42)
svm_clf = SVC(gamma="auto", probability=True, random_state=42)  # probability=True 하면 속도는 느리지만 soft voting이 가능

voting_clf = VotingClassifier(
    estimators=[('lr', log_clf), ('rf', rnd_clf), ('svc', svm_clf)],
    voting='soft')  # voting='hard'
voting_clf.fit(X_train, y_train)

for clf in (log_clf, rnd_clf, svm_clf, voting_clf):
    clf.fit(X_train, y_train)
    y_pred = clf.predict(X_test)
    print(clf.__class__.__name__, accuracy_score(y_test, y_pred))


2. Bagging and pasting

  • Bagging (Bootstrap aggregating)
    학습 데이터에서 중복을 허용하고 샘플링하여 분류기를 각기 다르게 학습시키고 voting 혹은 평균을 내어 예측하는 방법
    각 예측기가 학습하는 subset이 다양성을 증가시키기 때문에 ($_m\Pi_s > \ _mC_s$) bagging이 pasting보다 bias가 조금 더 높지만, 예측기들의 상관관계를 줄이므로 ensemble의 variance를 감소시킵니다. 일반적으로 pasting보다 bagging을 더 선호합니다.
  • Pasting
    학습 데이터에서 중복을 허용하지 않고 샘플링하여 분류기를 각기 다르게 학습시키고 voting 혹은 평균을 내어 예측하는 방법

SklearnBaggingClassifierpredict_proba()가 존재하면 soft voting으로 수행합니다.

1
2
3
4
5
6
7
8
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier


bag_clf = BaggingClassifier(
    DecisionTreeClassifier(random_state=42), n_estimators=500,
    max_samples=100, bootstrap=True, n_jobs=-1, random_state=42)
bag_clf.fit(X_train, y_train)

oob (Out-of-Bag) evaluation

Sample의 크기를 총 학습 데이터와 동일하게 사용하는 bagging의 경우, 학습 데이터의 약 63.2% 만을 학습에 사용합니다. (.632 bootstrap)
선택되지 않은 나머지 약 37% 데이터를 oob (out-of-bag) sample이라고 부릅니다.

oob sample은 예측기가 보지 못한 데이터이기 때문에 이들에 대한 score로 ensemble을 평가할 수 있습니다.

1
2
3
4
5
bag_clf = BaggingClassifier(
    DecisionTreeClassifier(random_state=42), n_estimators=500,
    bootstrap=True, n_jobs=-1, oob_score=True, random_state=40)
bag_clf.fit(X_train, y_train)
bag_clf.oob_score_


3. Random Patches method and Random Subspaces method

학습 데이터를 sampling 했던 기존의 방법들과는 다르게 몇 개의 feature만을 sampling하여 학습시키는 방법입니다. 특히 이미지와 같은 매우 고차원의 데이터셋을 다룰 때 유용합니다.

  • Random Patches method
    Sample과 feature 모두 sampling하는 방법
  • Random Subspaces method
    모든 sample을 사용하고 feature만 sampling하는 방법
    bootstrap=False, max_samples=1.0, bootstrap_features=True, max_feature=0.2


4. Random Forest

일반적으로 bagging (max_samples=1.0)을 적용한 decision tree의 ensemble입니다.
Tree의 node를 분할할 때 무작위로 선택한 feature 후보 중에서 최적의 feature를 찾는 식으로 무작위성을 추가로 주입합니다. 결국 bias는 높아지게 되지만, variance를 낮추어 전체적으로 더 훌륭한 모델이 만들어집니다.

1
2
3
4
5
from sklearn.ensemble import RandomForestClassifier


rnd_clf = RandomForestClassifier(n_estimators=500, max_leaf_nodes=16, n_jobs=-1, random_state=42)
rnd_clf.fit(X_train, y_train)

Extra-Trees (Extremely Randomized Trees)

Tree를 더욱 무작위하게 만들기 위해 최적의 임계값을 찾는 대신 후보 feature를 사용해 무작위로 분할한 다음 그중에서 최상의 분할을 선택하는 방법입니다.
SklearnExtraTreesClassifier을 사용할 수 있습니다.

Feature importance

Random forest의 한 가지 장점은 feature의 중요도를 측정하기 쉽다는 것입니다. 따라서 feature selection 시 어떤 feature가 중요한지 빠르게 확인할 수 있어 매우 편리합니다.
Feature의 중요도는 어떤 feature를 사용한 node가 평균적으로 impurity를 얼마나 감소시키는지 확인하여 측정합니다.

1
2
3
4
5
6
7
8
from sklearn.datasets import load_iris


iris = load_iris()
rnd_clf = RandomForestClassifier(n_estimators=10, random_state=42)
rnd_clf.fit(mnist["data"], mnist["target"])
for name, score in zip(iris['feature_names'], rnd_clf.feature_importances_):
  print(name, score)


5. Boosting (Hypothesis boosting)

약한 학습기를 여러 개 연결하여 강한 학습기를 만드는 ensemble method입니다.
이전의 모델을 보완해나가면서 일련의 예측기를 학습시키는 sequential algorithm으로 AdaBoost (Adaptive Boosting)Gradient Boosting이 가장 많이 사용되고 있습니다.

AdaBoost

이전 모델이 underfitting되었던 학습 데이터의 가중치를 더 높여 다음 모델을 학습시키는 방법입니다.
예를 들어, 먼저 첫 번째 분류기를 학습 데이터로 학습시키고 예측을 만듭니다. 잘못 분류된 학습 데이터의 가중치를 상대적으로 높인 후, 두 번째 분류기는 업데이트된 가중치를 사용해 학습 데이터로 학습시키고 다시 예측을 만듭니다. 이 과정을 반복하여 여러 개의 모델들을 생성하고 최종적으로 각 모델들에 다른 가중치를 적용시켜 예측합니다.

1
2
3
4
5
6
7
from sklearn.ensemble import AdaBoostClassifier


ada_clf = AdaBoostClassifier(
    DecisionTreeClassifier(max_depth=1), n_estimators=200,
    algorithm="SAMME.R", learning_rate=0.5, random_state=42)
ada_clf.fit(X_train, y_train)

Gradient Boosting

Adaboost가 sample의 가중치를 수정하는 것과 달리, 이전 예측기가 만든 residual error (잔여 오차)에 새로운 예측기를 학습시키는 방법입니다.
특히 decision tree를 기반 예측기로 하는 gradient boosting 회귀 모델을 Gradient Boosted Regression Tree (GBRT, Gradient Tree Boosting)라고 합니다.
각 tree의 기여 정도(learning_rate)를 조절할 때, 0.1과 같이 낮게 설정하고 많은 개수의 예측기를 사용하면 일반적으로 예측의 성능이 좋아지는데 이는 regularization의 일종으로 shrinkage (축소)라고 부르는 방법입니다.
다른 hyperparameter와 마찬가지로 예측기의 개수도 early stopping 등을 사용하여 정할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from sklearn.tree import DecisionTreeRegressor


tree_reg1 = DecisionTreeRegressor(max_depth=2, random_state=42)
tree_reg1.fit(X, y)

y2 = y - tree_reg1.predict(X)
tree_reg2 = DecisionTreeRegressor(max_depth=2, random_state=42)
tree_reg2.fit(X, y2)

y3 = y2 - tree_reg2.predict(X)
tree_reg3 = DecisionTreeRegressor(max_depth=2, random_state=42)
tree_reg3.fit(X, y3)

y_pred = sum(tree.predict(X_new) for tree in (tree_reg1, tree_reg2, tree_reg3))

### GradientBoostingRegressor API
from sklearn.ensemble import GradientBoostingRegressor


gbrt = GradientBoostingRegressor(max_depth=2, n_estimators=3, learning_rate=1.0)
gbrt.fit(X, y)

6. Stacking (Stacked generalization, blending)

Ensemble에 속한 모든 예측기들 뿐만 아니라 이들의 예측을 취합하는 모델(blender, meta learner)도 학습시키는 방법입니다.
Blender를 학습시키는 일반적인 방법은 다음과 같습니다.

  1. 학습 데이터를 2개의 subset으로 나눈다.
  2. 첫 번째 subset은 첫 번째 레이어(ensemble)의 예측을 훈련시키기 위해 사용한다.
  3. 두 번째 subset(hold-out)에 대한 첫 번째 레이어의 예측을 input feature로 사용하여 blender를 학습시킨다.

이와 같은 방식으로 학습 데이터를 여러 개의 subset으로 나누고 다수의 blender를 학습시키는 것도 가능합니다.