#!/usr/bin/env python3


Gradient Boosting Model


gradient boosting regression tree는 여러 개의 decision tree를 묶어 강력한 model을 만드는 ensemble기법입니다.

random forest와 달리 gradient boosting model은 이전 tree의 오차를 보완하는 방식으로 tree를 만듭니다.


gradient boosting은 무작위성이 없어 powerful한 pre-pruning이 사용되며

1~5 정도 깊이의 tree를 사용하므로 메모리를 적게 사용하고 예측도 빠릅니다.


gradient boosting은 이런 얕은 트리들을 계속해서 연결해나가는 것입니다.


gradient boosting은 parmeter설정에 random forest보다 조금 더 민감하지만 잘 조정하면 높은 정확도를 제공합니다.


gradinet boosting에서 주요 parameter는 이전 트리의 오차를 얼마나 강하게 보정할 것인가를 제어하는

learning_rate가 있습니다.


learning_rate를 높이면 보정을 강하게 하기 때문에 복잡한 모델을 만듭니다.

n_estimator 값을 키우면 ensemble에 트리가 더 많이 추가되어 모델의 복잡도가 커지고 train 세트를 더 정확하게 fitting합니다.


Breast Cancer datasets으로 GradientBoostingClassifier을 적용해보겠습니다.

from sklearn.ensemble import GradientBoostingClassifier

from sklearn.model_selection import train_test_split

from sklearn.datasets import load_breast_cancer


cancer = load_breast_cancer()


x_train, x_test, y_train, y_test = train_test_split(cancer.data, cancer.target, 

                                                    stratify=cancer.target, random_state=0)


gbc = GradientBoostingClassifier(random_state=0) # 기본값: max_depth=3, learning_rate=0.1

gbc.fit(x_train, y_train)


score_train = gbc.score(x_train, y_train) # train set 정확도

print('{:.3f}'.format(score_train))

# 1.000


score_test = gbc.score(x_test, y_test) # 일반화 정확도

print('{:.3f}'.format(score_test))

# 0.958

훈련세트의 정확도가 100%이므로 overfitting입니다.



overfitting을 막기 위해 트리의 깊이를 줄여 pre-pruning을 강하게 하겠습니다.

gbc = GradientBoostingClassifier(random_state=0, max_depth=1)

gbc.fit(x_train, y_train)


score_train_pre = gbc.score(x_train, y_train) # train set 정확도

print('{:.3f}'.format(score_train_pre))

# 0.995


score_test_pre = gbc.score(x_test, y_test) # 일반화 정확도

print('{:.3f}'.format(score_test_pre))

# 0.965

이전에 비해 train_set는 낮아졌고, test set의 정확도는 높아졌으므로 모델이 향상된 것을 볼 수 있습니다.



이번에는 learning_rate 조절하여 overfitting을 해결하겠습니다.

gbc = GradientBoostingClassifier(random_state=0, max_depth=3, learning_rate=0.01) # 기본값 0.1

gbc.fit(x_train, y_train)


score_train_lr = gbc.score(x_train, y_train)

print('{:.3f}'.format(score_train_lr))

# 0.995


score_test_lr = gbc.score(x_test, y_test) 

print('{:.3f}'.format(score_test_lr))

# 0.944



위의 결과를 시각화하는 코드는 다음과 같습니다.

import matplotlib

import matplotlib.pyplot as plt

import numpy as np


score_set = np.round([score_train, score_test], 3)

max_depth_score_set = np.round([score_train_pre, score_test_pre], 3)

learning_rete_score_set = np.round([score_train_lr, score_test_lr], 3)


index = np.arange(len(score_set))

bar_width = 0.35

bottom = 0.8

list_set = [max_depth_score_set, learning_rete_score_set]

line_set = ['--', ':']

names = ['train', 'test']


for i, line_set, name in zip(index, line_set, names):

    plt.hlines(score_set[i], xmin=0-bar_width,

               xmax=index[-1]+2*bar_width,

               linestyle=line_set, label='default {}'.format(name))

    plt.text(0-bar_width, score_set[i]+0.005, str(score_set[i]))


plt.bar(index, max_depth_score_set, width=bar_width, label='adj max_depth')

plt.bar(index+bar_width, learning_rete_score_set, width=bar_width, label='adj learning rate')

for i, ts, te in zip(index, max_depth_score_set, learning_rete_score_set):

    plt.text(i, (bottom+ts)/2, str(ts), horizontalalignment='center')

    plt.text(i+bar_width, (bottom+te)/2, str(te), horizontalalignment='center')


plt.ylim(bottom, 1.05)

plt.xticks(index+bar_width/2, names)

plt.ylabel('score', size=15)

plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.1), ncol=4, fancybox=True, shadow=False)

plt.show()

max_depth와 learning rate를 조절한 random forest의 score

위 2가지 방식은 model의 복잡도를 감소시키므로 train 세트의 정확도가 낮아졌습니다.

이 예에서 learning_rate를 낮추는 것은 일반화 정확도의 성능을 조금밖에 개선하지 못했지만, 

트리의 최대 깊이를 낮추는 것은 model 성능 향상에 크게 기여한것을 볼 수 있습니다.



max_depth=1일 때 특성 중요도를 시각화 하는 코드는 다음과 같습니다. 

gbc = GradientBoostingClassifier(max_depth=1, random_state=0)

gbc.fit(x_train, y_train)

n_feature = cancer.data.shape[1]

index=np.arange(n_feature)


plt.barh(index, gbc.feature_importances_, align='center')

plt.yticks(index, cancer.feature_names)

plt.xlabel('feature importances', size=15)

plt.ylabel('feature', size=15)

plt.show() 

breast cancer data로 만든 GradientBoostingClassifier의 feature importances

GradientBoostingClassifier의 특성 중요도와 RandomForestClassifier의 특성 중요도가 비슷합니다.

그러나 GradientBoostingClassifier은 일부 특성을 완전 무시합니다.


보통 더 안정적인 RandomForest를 먼저 적용하고 GradientBoosting을 사용하고

예측 시간이 중요하거나, machine learning model에서 마지막 성능까지 사용할 때 많이 사용



참고 자료: 

[1]Introduction to Machine Learning with Python, Sarah Guido

'python 머신러닝 -- 지도학습 > Classifier' 카테고리의 다른 글

Neural Network(Deep Learning)  (0) 2018.03.17
Kernelized Support Vector Machines  (0) 2018.03.15
Random Forest  (0) 2018.03.15
Decision Tree  (0) 2018.03.14
Multi Linear Classification  (0) 2018.03.14

+ Recent posts