일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 군집화기법
- 실제데이터활용
- cost complexity pruning
- 최소제곱법
- 선형모형
- 의사결정나무
- AdaBoostRegressor
- gradientdescent
- 중선형회귀
- 경사하강법
- 아다부스트
- 사후 가지치기
- 정보이득
- LinearRegression
- post pruning
- boosting
- 부스팅기법
- 사전 가지치기
- 캘리포니아주택가격예측
- 회귀분석
- C4.5
- MultipleLinearRegression
- Adaboost
- 부스팅
- AdaBoostClassifier
- pre pruning
- LeastSquare
- 체인지업후기
- KNearestNeighbors
- 선형회귀
- Today
- Total
데이터 분석을 향한 발자취 남기기
[Boosting] Gradient Boosting Regressor 본문
오늘은 Gradient Boosting 알고리즘을 회귀에 적용해보려고 한다.
1. Gradient Boosting Regressor Algorithm
2. Simple example
3. Sklearn GradientBoostingRegressor 비교
1. Gradient Boosting Regressor Algorithm
Gradient Boosting은 Boosting 기반 알고리즘으로 약한 학습기들을 앙상블하여 더 좋은 성능을 얻는 예측 모델을 생성하는 방법이다. 일반적으로 Bagging의 대표적인 알고리즘인 Random Forest보다 더 좋은 성능을 보인다. 핵심은 각 약한 학습기를 생성할 때, 미분 가능한 손실 함수를 최소화하는 방향으로 학습한다는 것이다. 이때, 손실함수 최적화 방법으로 경사하강법(Gradient Descent)를 사용한다.
- 미분 가능한 손실함수
실제값 $y$와 예측값 $F(x)$가 주어졌을 때, 이들의 미분 가능한 손실함수 $L$은 다음과 같다. 일반적으로 미분 가능한 손실함수로 잔차 제곱합을 사용한다.
이를 예측값 $F(x)$로 미분하게 되면 다음과 같이 예측값과 실제값의 차이로 나타난다.
즉, 잔차는 음의 손실함수 기울기와 같음을 알 수 있다.
Gradient Boosting 회귀 알고리즘은 다음과 같다.
초기에 손실을 최소화하는 상수값으로 트리를 생성한다. 즉 아래와 같이 단순히 root node가 leaf node가 되는 트리를 생성해둔다. 이때, 손실을 최소화하는 상수값은 결국 훈련 데이터 $y$값들의 평균이 된다(*).
* $F_{0}(x)$ = 훈련 데이터 $y$의 평균($\bar{y}$)
이를 이용해 잔차를 계산하고, 그다음 트리는 훈련 데이터의 $x$를 사용해 잔차 $r$를 예측하는 모델을 생성한다. 이때, 트리는 깊게 생성될 수 있다.
각 트리들의 예측값들을 모두 더해서 예측값을 업데이트한다. 이때, 각 트리는 훈련 데이터의 잔차를 학습하기 때문에 과적합되기 쉬우므로 학습률 $\eta$을 이용해 각 트리의 영향력을 제한한다. 이를 반복하면서, 예측값을 업데이트하게 된다.
2. Simple example
간단한 예제를 이용해서 Gradient Boosting 회귀 모형을 이해하고자 한다. AdaBoost 회귀 모형 때, 사용한 데이터와 동일하게 50개의 simulation 데이터를 생성하였다.
먼저, 손실을 최소화하는 상수값을 계산한다. 앞에서 설명했듯이, 이는 훈련 데이터 $y$의 평균값으로 계산된다.
- $t = 1$
50개 데이터에 대해서, $\bar{y}$로 예측했을 때, 얻어지는 잔차(실제값 - 예측값)를 계산한다.
그다음, 모든 $i$에 대해서, $X_{i}$와 잔차 $r_{i 1}$을 이용해 회귀모델을 생성한다.
즉, 회귀모델을 훈련하기 위한 데이터 셋은 $(X_{1}, r_{1 1}), \cdots , (X_{n}, r_{n 1})$이다. 이때, 회귀모델로 decision tree를 사용하였다. 그러면, 트리에 대한 leaf node가 계산이 된다. 이때, 계산된 leaf node의 개수를 $J_{t}$라 두고 각 leaf node를 $R_{j t}, for j = 1, \cdots , J_{t}$라 둔다.
예를 들어, 아래와 같은 그림의 트리가 생성되었다고 가정하자. 트리의 leaf node 개수는 총 6개로 $J_{t} = 6$이다. 이에 따라, 각 leaf node의 값은 $R_{1 t}, \cdots , R_{6 t}$임을 볼 수 있다.
이제, 각 leaf node에 대해 손실을 최소화하는 $\gamma_{j t}$을 계산한다. 이때, 우리는 잔차를 예측하는 트리를 생성했기 때문에 이전 트리의 예측값과 $\gamma$를 더해 새로운 예측값을 생성해야한다.
식은 복잡해보이지만, 각 leaf node마다 손실을 최소화하는 $\gamma_{j t}$는 결국 해당 leaf node 내 $r_{i}$들의 평균이 된다(*).
* $\gamma_{j t}$
즉, 각 leaf node의 평균값으로 잔차를 예측한다. 아래 그림은 실제 예제에 대한 회귀모형을 생성하고 이에 대한 잔차 예측값을 생성하는 과정을 나타냈다. $R_{1 1}$은 하나의 샘플만 포함하기 때문에, 이에 대한 예측값은 해당 샘플에 대한 잔차임을 볼 수 있다. → $r_{i 1}$ = $\gamma_{j 1}$
반면, $R_{2 1}$은 4개의 샘플이 속하므로, 이들의 잔차 평균값으로 $\gamma_{2 1}$이 계산됨을 볼 수 있다.
이제 마지막으로 예측값을 업데이트 한다. 즉, 이전에 구한 예측값에 대해서, 회귀모형을 통해 구한 잔차 예측값을 더해줌으로써 업데이트한다. 이때, $\eta$는 각 회귀모형들의 영향력을 제어하기 위해 사용되며, 예제에서는 0.03으로 설정하여 사용했다.
이제, 다시 잔차를 계산하고 예측값을 업데이트하는 작업을 반복한다.
3. Sklearn GradientBoostingRegressor 비교
직접 짠 Gradient Boosting 회귀 모델(Hand)와 sklearn의 GradientBoostingRegressor를 비교해보려고 한다.
회귀모형으로 DecisionTreeRegressor을 사용했으며, 트리의 깊이는 4로 제한하였다. 총 100개의 트리를 생성하도록 했을 때, 예측결과는 아래와 같다.

그 결과, 두 모델 모두 데이터의 분포를 잘 따르고 있음을 볼 수 있다. 두 모델의 예측값이 실제로 동일한지 알아보기 위해, Sklearn 예측값과 hand 예측값 간 분포를 살펴보았다. 빨간색 대각선 위에 점이 위치하면 두 모델의 예측값이 일치한다고 볼 수 있는데, 모든 예측값이 일치함을 볼 수 있다. 직접 짠 모델과 Sklearn의 모델의 예측값이 일치하는 것으로 보아, 모델이 제대로 생성되었음을 알 수 있다.
GradientBoosting Regressor 훈련 및 성능 비교 코드 ↓
'''
Gradient Boosting
Regressor
'''
import numpy as np
from sklearn.tree import DecisionTreeRegressor
# 데이터 생성
rng = np.random.RandomState(123)
X = np.linspace(0, 6, 50)[:, np.newaxis]
y = np.sin(X).ravel()+np.sin(6*X).ravel() + rng.normal(0, 0.1, X.shape[0])
# 트리 개수 및 깊이
T, tree_depth = 100, 4
# 초기 학습률 및 초기 트리 생성
alpha = 0.03
F_0 = [np.mean(y) for x in range(len(X))]
# 잔차 학습한 모델 추가
model_list = []
for i in range(T):
# 잔차 계산
rr = y-F_0
# 회귀모델 학습
dt = DecisionTreeRegressor(max_depth = tree_depth).fit(X, rr)
model_list.append(dt)
# 예측값 업데이트
# DecisionTreeRegressor는 예측 시, leaf node의 평균값으로 예측하므로
# 예측값 그대로 사용함
F_0 = F_0 + alpha * dt.predict(X)
'''
Sklearn vs Hand
'''
from sklearn.ensemble import GradientBoostingRegressor
import matplotlib.pyplot as plt
from sklearn.metrics import mean_absolute_error, mean_squared_error
# 트리 깊이, learning rate(학습률), 트리 개수 설정
gbm = GradientBoostingRegressor(max_depth = tree_depth, learning_rate = alpha, n_estimators = T).fit(X, y)
gbm_pred = gbm.predict(X)
fig, ax = plt.subplots(ncols = 2, figsize = (10, 5))
ax[0].scatter(X, y)
ax[0].plot(X, F_0, color = "black", label = "Hand")
ax[0].plot(X, gbm_pred, color = "red", label = "Sklearn")
ax[0].legend()
ax[1].scatter(gbm_pred, F_0, color = "black", zorder = 2)
ax[1].set_xlabel("Sklearn pred")
ax[1].set_ylabel("Hand pred")
a, b = ax[1].set_xlim()
ax[1].plot([a, b], [a, b], color = "red", zorder = 1)
ax[1].set_xlim(a, b)
ax[1].set_ylim(a, b)
plt.tight_layout(w_pad = 2)
print("Sklearn", "MAE:", round(mean_absolute_error(y, gbm_pred), 3), "RMSE:", round(mean_squared_error(y, gbm_pred, squared = False), 3))
print("Hand", "MAE:", round(mean_absolute_error(y, F_0), 3), "RMSE:", round(mean_squared_error(y, F_0, squared = False), 3))
오늘은 Gradient Boosting을 회귀 문제에서 어떻게 사용하는지 알아보았다. Gradient Boosting은 Kaggle에서도 많이 활용되는 모델이면서, 복잡한 수학적 개념들로 구성되어있다. 이번 장에서는 단순하게 모델 생성에 집중해서 이해했지만, 아래 블로그를 참고해 더 깊게 공부해서 다시 올리고자 한다. 화이팅,,
https://zephyrus1111.tistory.com/224
20. Gradient Boosting 알고리즘에 대해서 알아보자 with Python
이번 포스팅에서는 Gradient Boosting의 개념과 알고리즘을 소개하며 이를 응용한 Gradient Tree Boosting의 개념과 알고리즘도 소개한다. 그리고 Gradient Tree Boosting 알고리즘을 파이썬으로 직접 구현하는
zephyrus1111.tistory.com
'손으로 직접 해보는 모델정리 > 앙상블 모델' 카테고리의 다른 글
[Boosting] AdaBoost Classifier with Citrus (0) | 2023.04.12 |
---|---|
[Boosting] AdaBoost Regressor (0) | 2023.03.28 |
[Boosting] AdaBoost Classifier (0) | 2023.03.24 |
앙상블 학습 방법 (0) | 2023.03.24 |