5.8 회귀 트리
트리 기반의 회귀는 회귀 트리를 이용 하는 것입니다. 즉 ,회귀를 위한 트리를 생성하고 이를 기반으로 회귀 예측을 하는 것이다.
회귀 트리는 분류 트리와 크게 다르지 않지만, 리프 노드에서 예측 결정 값을 만드는 과정에서 차이가 있다.
분류 트리가 특정 클래스 레이블을 결정하는 것과 달리 회귀 트리는 리프 노드에 속한 데이터 값의 평균값을 구해 회귀 예측값을 계산한다.
매우 간단한 데이터 셋을 이용해 회귀 트리가 어떻게 동작하는 지살펴보자.
피처가 단 하나인 X 피처 데이터 셋과 결정값 Y가 2차원 평면상에 다음과 같이 있다고 가정하자.
이 데이터 셋의 X 피처를 트리 기반으로 분할하면 X값의 균일도를 반영한 지니 계수에 따라 루트 노드를 Split 0 기준으로 분할하고,
이렇게 분할된 규칙 노드에서 다시 Split1과 Split2 규칙 노드로 분할 할 수 있다.
그리고 Split 2는 다시 재귀적으로 Split3 규칙 노드로 분할 할 수 있다.
리프 노드 생성 기준에 부합하는 트리 분할이 완료 됐다면 리프 노드에 소속된 데이터 값의 평균값을 구해서 최종적으로 리프 노드에 결정 값으로 할당합니다.
사이킷런에서는 결정 트리, 랜덤 포레스트 ,GBM에서 CART 기반의 회귀 수행을 할 수 있는 Estimator 클래스를 제공한다. 또한 XGBoost, LightGBM도 사이킷런 래퍼클래스를 통해 이를 제공한다.
알고리즘 | 회귀 Estimator 클래스 | 분류 Estimator 클래스 |
---|---|---|
Decision Tree | Decision Tree Regressor | Decision Tree Classifier |
Gradient Boosting | Gradient Boosting Regressor | Gradient Boosting Classifier |
XGBoost | XGBRegressor | XGBClassifier |
LightGBM | LGBMRegressor | LGBMClassifier |
회귀 트리 실습 - 보스턴 주택 가격 예측
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
import pandas as pd
import numpy as np
# 보스턴 데이터 세트 로드
boston = load_boston()
bostonDF = pd.DataFrame(boston.data, columns = boston.feature_names)
bostonDF['PRICE'] = boston.target
y_target = bostonDF['PRICE']
X_data = bostonDF.drop(['PRICE'], axis=1,inplace=False)
rf = RandomForestRegressor(random_state=0, n_estimators=1000)
neg_mse_scores = cross_val_score(rf, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
print(' 5 교차 검증의 개별 Negative MSE scores: ', np.round(neg_mse_scores, 2))
print(' 5 교차 검증의 개별 RMSE scores : ', np.round(rmse_scores, 2))
print(' 5 교차 검증의 평균 RMSE : {0:.3f} '.format(avg_rmse))
5 교차 검증의 개별 Negative MSE scores: [ -7.92 -13.03 -20.51 -46.35 -18.95]
5 교차 검증의 개별 RMSE scores : [2.81 3.61 4.53 6.81 4.35]
5 교차 검증의 평균 RMSE : 4.423
이번에는 회귀 트리 Regressor 가 어떻게 예측값을 판단하는지 선형 회귀와 비교해 시각화 해보자.
def get_model_cv_prediction(model, X_data, y_target):
neg_mse_scores = cross_val_score(model, X_data, y_target, scoring="neg_mean_squared_error", cv = 5)
rmse_scores = np.sqrt(-1 * neg_mse_scores)
avg_rmse = np.mean(rmse_scores)
print('##### ',model.__class__.__name__ , ' #####')
print(' 5 교차 검증의 평균 RMSE : {0:.3f} '.format(avg_rmse))
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
import numpy as np
import pandas as pd
%matplotlib inline
# boston 데이타셋 로드
boston = load_boston()
# boston 데이타셋 DataFrame 변환
bostonDF = pd.DataFrame(boston.data , columns = boston.feature_names)
# boston dataset의 target array는 주택 가격임. 이를 PRICE 컬럼으로 DataFrame에 추가함.
bostonDF['PRICE'] = boston.target
y_target = bostonDF['PRICE']
X_data = bostonDF.drop('PRICE',axis=1,inplace = False)
dt_reg = DecisionTreeRegressor(random_state=0, max_depth=4)
rf_reg = RandomForestRegressor(random_state=0, n_estimators=1000)
gb_reg = GradientBoostingRegressor(random_state=0, n_estimators=1000)
xgb_reg = XGBRegressor(n_estimators=1000)
lgb_reg = LGBMRegressor(n_estimators=1000)
# 트리 기반의 회귀 모델을 반복하면서 평가 수행
models = [dt_reg, rf_reg, gb_reg, xgb_reg, lgb_reg]
for model in models:
get_model_cv_prediction(model, X_data, y_target)
##### DecisionTreeRegressor #####
5 교차 검증의 평균 RMSE : 5.978
##### RandomForestRegressor #####
5 교차 검증의 평균 RMSE : 4.423
##### GradientBoostingRegressor #####
5 교차 검증의 평균 RMSE : 4.269
##### XGBRegressor #####
5 교차 검증의 평균 RMSE : 4.251
##### LGBMRegressor #####
5 교차 검증의 평균 RMSE : 4.646
Price와 가장 밀접한 양의 상관관계를 가지는 RM칼럼만 이용해 선형 회귀와 결정 트리 회귀로 PRICE 예측 회귀선을 표현해보자.
보스턴 데이터 셋의 개수를 100개만 샘플링하고 RM과 PRICE 칼럼만 추출하겠습니다
.
2차원 평면상에서 X 축에 독립변수인 RM, Y 축에 종속변수인 PRICE만을 가지고 좀 더 직관적으로 예측값을 시각화하기 위한 것이다.
이 데이터 셋을 산점도 형태로 살펴 봅니다.
import seaborn as sns
%matplotlib inline
rf_reg = RandomForestRegressor(n_estimators=1000)
# 앞 예제에서 만들어진 X_data, y_target 데이터 셋을 적용하여 학습합니다.
rf_reg.fit(X_data, y_target)
feature_series = pd.Series(data=rf_reg.feature_importances_, index=X_data.columns )
feature_series = feature_series.sort_values(ascending=False)
sns.barplot(x= feature_series, y=feature_series.index)
<matplotlib.axes._subplots.AxesSubplot at 0x161437c3508>
import matplotlib.pyplot as plt
%matplotlib inline
bostonDF_sample = bostonDF[['RM','PRICE']]
bostonDF_sample = bostonDF_sample.sample(n=100,random_state=0)
print(bostonDF_sample.shape)
plt.figure()
plt.scatter(bostonDF_sample.RM , bostonDF_sample.PRICE,c="darkorange")
(100, 2)
다음으로 보스턴 데이터 셋에 대해 LinearRegression과 DecisionTreeRegressor을 max_depth를 각각 2, 7 로해서 학습해 보겠습니다.
이렇게 학습된 Regressor 에 RM 값을 4.5~8.5 까지의 100개의 테스트 데이터 셋을 제공했을 때 예측 값을 구하겠습니다.
import numpy as np
from sklearn.linear_model import LinearRegression
# 선형 회귀와 결정 트리 기반의 Regressor 생성. DecisionTreeRegressor의 max_depth는 각각 2, 7
lr_reg = LinearRegression()
rf_reg2 = DecisionTreeRegressor(max_depth=2)
rf_reg7 = DecisionTreeRegressor(max_depth=7)
# 실제 예측을 적용할 테스트용 데이터 셋을 4.5 ~ 8.5 까지 100개 데이터 셋 생성.
X_test = np.arange(4.5, 8.5, 0.04).reshape(-1, 1)
# 보스턴 주택가격 데이터에서 시각화를 위해 피처는 RM만, 그리고 결정 데이터인 PRICE 추출
X_feature = bostonDF_sample['RM'].values.reshape(-1,1)
y_target = bostonDF_sample['PRICE'].values.reshape(-1,1)
# 학습과 예측 수행.
lr_reg.fit(X_feature, y_target)
rf_reg2.fit(X_feature, y_target)
rf_reg7.fit(X_feature, y_target)
pred_lr = lr_reg.predict(X_test)
pred_rf2 = rf_reg2.predict(X_test)
pred_rf7 = rf_reg7.predict(X_test)
LinearRegreesion 과 DecisionTreeRegressor의 max_depth를 각각 2, 7로 해서 학습된 Regressor에서 예측한 Price 회귀선을 그려보자..
fig , (ax1, ax2, ax3) = plt.subplots(figsize=(14,4), ncols=3)
# X축값을 4.5 ~ 8.5로 변환하며 입력했을 때, 선형 회귀와 결정 트리 회귀 예측 선 시각화
# 선형 회귀로 학습된 모델 회귀 예측선
ax1.set_title('Linear Regression')
ax1.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax1.plot(X_test, pred_lr,label="linear", linewidth=2 )
# DecisionTreeRegressor의 max_depth를 2로 했을 때 회귀 예측선
ax2.set_title('Decision Tree Regression: \n max_depth=2')
ax2.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax2.plot(X_test, pred_rf2, label="max_depth:3", linewidth=2 )
# DecisionTreeRegressor의 max_depth를 7로 했을 때 회귀 예측선
ax3.set_title('Decision Tree Regression: \n max_depth=7')
ax3.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax3.plot(X_test, pred_rf7, label="max_depth:7", linewidth=2)
선형 회귀는 직선으로 예측 회귀선을 표현하는데 반해 , 회귀 트리의 경우 분할되는 데이터 지점에 따라 브랜치를 만들면서 계단 형태로 회귀선을 만든다.
DecisionTreeRegressor 의 max_depth = 7 인 경우에는 학습 데이터 셋의 이상치 데이터도 학습하면서 복잡한 계단 형태의 회귀선을 만들어 과적합이 되기 쉬운 모델이 되었음을 알 수 있다.
본문 내용은 파이썬 머신러닝 완벽 가이드 (권철민 저)을 요약정리한 내용입니다.