위키북스의 파이썬 머신러닝 완벽 가이드 책을 토대로 공부한 내용입니다.


1. 회귀 트리


선형 회귀는 회귀 계수의 관계가 모두 선형이라고 가정하는 방식이며, 비선형 회귀 역시 회귀 계구의 관계가 비선형 회귀라고 가정하는 방식이다. 머신러닝 기반의 회귀는 회귀 계수를 기반으로 하는 최적 회귀 함수를 도출하는 것이 주요 목표이다. 하지만 회귀 함수를 기반으로 하지 않고 결정 트리와 같이 트리를 기반으로 하는 회귀 방식도 있다. 회귀를 위한 트리를 생성하고 이를 기반으로 회귀 예측을 하는 것이다. 4장의 분류 트리와 크게 다르지 않지만 리프 노드에서 예측 결정 값을 만드는 과정에 차이가 있는데, 분류 트리가 특정 클래스 label을 결정하는 것과 달리 회귀 트리는 리프 노드에 속한 데이터의 평균을 구해 회귀 예측값을 계산한다.

만약 feature가 하나만 있는 X feature dataset과 결정값 Y가 있다고 가정해보면, 결정 트리 기반으로 분할하면 X값의 균일도를 빈영한 지니 계수에 따라 규칙 노드들이 생기며 분할될 것이다. 리프 노드 생성 기분에 부합하는 트리 분할이 완료됬다면 리프 노드에 소속된 데이터 값의 평균값을 구해서 최종적으로 리프 노드에 결정 값으로 할당한다.

4장의 분류에서 소개한 모든 트리 기반의 알고리즘은 분류뿐만 아니라 회귀도 가능하다. 트리 생성이 CART(Classification And Regression Trees) 알고리즘에 기반하고 있기 때문이다.

알고리즘회귀 Estimator 클래스분류 Estimator 클래스
Decision Tree
DecisionTreeRegressor
DecisionTreeClassifier
Gradient Boosting
GradientBoostingRegressor
GradientBoostingClassifier
RandomForest
RandomForestRegressor
RandomForestClassifier
XGBoost
XGBRegressor
XGBClassifier
LightGBM
LGBMRegressor
LGBMClassifier

위 4 종류의 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))

import pandas as pd
import numpy as np
from sklearn.datasets import load_boston
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import GradientBoostingRegressor
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor

# 보스턴 데이터 세트 로드
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)

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)

[output] 회귀 트리 Regressor 클래스는 classifier와 동일하게 featureimfortances를 이용해 feature 별 중요도를 알 수 있다.

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)

[output] 이번에는 회귀 트리 Regressor가 어떻게 예측값을 판단하는지 선형 회귀와 비교해 시각화해보겠다. 결정 트리의 hyper parameter인 max_depth를 변화시키면서 회귀 트리 예측선이 어떻게 변화하는지 살펴보겠다. 보스턴 주택 dataset의 여러 column 중에서 Price와 가장 관련이 있는 RM column만을 이용하여 선형 회귀와 결정 트리 호귀로 2차원 예측 회귀선을 표현해보겠다.

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.linear_model import LinearRegression

bostonDF_sample = bostonDF[['RM','PRICE']]
bostonDF_sample = bostonDF_sample.sample(n=100,random_state=0)

# 선형 회귀와 결정 트리 기반의 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)

fig , (ax1, ax2, ax3, ax4) = plt.subplots(figsize=(14,4), ncols=4)

# X축값을 4.5 ~ 8.5로 변환하며 입력했을 때, 선형 회귀와 결정 트리 회귀 예측 선 시각화
ax1.set_title('RM-Price data')
ax1.scatter(bostonDF_sample.RM , bostonDF_sample.PRICE, c="darkorange")

# 선형 회귀로 학습된 모델 회귀 예측선 
ax2.set_title('Linear Regression')
ax2.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax2.plot(X_test, pred_lr,label="linear", linewidth=2 )

# DecisionTreeRegressor의 max_depth를 2로 했을 때 회귀 예측선 
ax3.set_title('Decision Tree Regression: \n max_depth=2')
ax3.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax3.plot(X_test, pred_rf2, label="max_depth:3", linewidth=2 )

# DecisionTreeRegressor의 max_depth를 7로 했을 때 회귀 예측선 
ax4.set_title('Decision Tree Regression: \n max_depth=7')
ax4.scatter(bostonDF_sample.RM, bostonDF_sample.PRICE, c="darkorange")
ax4.plot(X_test, pred_rf7, label="max_depth:7", linewidth=2)

[output] 회귀 트리의 경우 분할되는 데이터 지점에 따라 브랜치를 만들면서 계단 형태로 회귀선을 만든다. max_depth가 7인 경우에는 학습 dataset의 outlier 데이터도 학습하면서 복잡한 계산 형태의 회귀선을 만들어 과적합이 되기 쉬운 모델이 되는 것을 알 수 있다.

profile
NLP, AI, LLM, MLops

0개의 댓글