047 결정 트리 회귀 상세
키워드: 결정 트리, 회귀
개요
결정 트리는 분류뿐만 아니라 회귀에도 사용됩니다. 비선형 관계를 포착할 수 있고 해석이 용이합니다.
실습 환경
- Python 버전: 3.11 권장
- 필요 패키지:
pycaret[full]>=3.0
결정 트리 회귀 원리
- 데이터를 재귀적으로 분할
- 각 리프 노드에서 평균값 예측
- MSE를 최소화하는 분할점 선택
[모든 데이터]
평균: 25.0
│
┌───────────┴───────────┐
│ │
[rm < 6.5] [rm >= 6.5]
평균: 18.0 평균: 35.0
PyCaret에서 결정 트리 회귀
from pycaret.regression import *
from pycaret.datasets import get_data
data = get_data('boston')
reg = setup(data, target='medv', session_id=42, verbose=False)
# 047 결정 트리 회귀
dt = create_model('dt')
주요 하이퍼파라미터
# 047 max_depth: 최대 깊이
dt_d3 = create_model('dt', max_depth=3)
dt_d5 = create_model('dt', max_depth=5)
dt_d10 = create_model('dt', max_depth=10)
# 047 min_samples_split: 분할 최소 샘플
dt_split = create_model('dt', min_samples_split=20)
# 047 min_samples_leaf: 리프 최소 샘플
dt_leaf = create_model('dt', min_samples_leaf=10)
# 047 max_features: 분할 시 고려할 특성
dt_sqrt = create_model('dt', max_features='sqrt')
깊이에 따른 성능 변화
from pycaret.regression import *
from pycaret.datasets import get_data
import pandas as pd
data = get_data('boston')
reg = setup(data, target='medv', session_id=42, verbose=False)
results = []
for depth in [2, 3, 5, 7, 10, 15, None]:
dt = create_model('dt', max_depth=depth, verbose=False)
metrics = pull()
results.append({
'depth': depth if depth else 'unlimited',
'MAE': metrics['MAE'].mean(),
'RMSE': metrics['RMSE'].mean(),
'R2': metrics['R2'].mean()
})
df = pd.DataFrame(results)
print(df)
# 047 깊이가 너무 깊으면 과적합
예측 시각화
import numpy as np
import matplotlib.pyplot as plt
# 1차원 예제로 결정 트리 회귀 이해
from sklearn.tree import DecisionTreeRegressor
np.random.seed(42)
X = np.sort(5 * np.random.rand(80, 1), axis=0)
y = np.sin(X).ravel() + np.random.randn(80) * 0.1
# 047 다양한 깊이의 트리
X_test = np.arange(0.0, 5.0, 0.01)[:, np.newaxis]
plt.figure(figsize=(12, 4))
for idx, depth in enumerate([2, 5, 10]):
plt.subplot(1, 3, idx + 1)
regr = DecisionTreeRegressor(max_depth=depth)
regr.fit(X, y)
y_pred = regr.predict(X_test)
plt.scatter(X, y, s=20, alpha=0.5, label='Data')
plt.plot(X_test, y_pred, color='red', linewidth=2, label='Prediction')
plt.title(f'max_depth={depth}')
plt.legend()
plt.tight_layout()
plt.savefig('dt_regression_depth.png', dpi=150)
트리 시각화
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
# 047 얕은 트리로 시각화
dt_shallow = create_model('dt', max_depth=3, verbose=False)
plt.figure(figsize=(20, 10))
plot_tree(
dt_shallow,
feature_names=list(get_config('X_train').columns),
filled=True,
rounded=True,
fontsize=10
)
plt.title('Decision Tree Regressor (max_depth=3)')
plt.tight_layout()
plt.savefig('dt_regression_tree.png', dpi=150)
특성 중요도
from pycaret.regression import *
from pycaret.datasets import get_data
import pandas as pd
data = get_data('boston')
reg = setup(data, target='medv', session_id=42, verbose=False)
dt = create_model('dt', max_depth=5, verbose=False)
# 047 특성 중요도
feature_names = get_config('X_train').columns
importances = dt.feature_importances_
importance_df = pd.DataFrame({
'Feature': feature_names,
'Importance': importances
}).sort_values('Importance', ascending=False)
print("특성 중요도:")
print(importance_df)
# 047 시각화
plot_model(dt, plot='feature')
튜닝
from pycaret.regression import *
from pycaret.datasets import get_data
data = get_data('boston')
reg = setup(data, target='medv', session_id=42, verbose=False)
dt = create_model('dt', verbose=False)
# 047 자동 튜닝
tuned_dt = tune_model(dt, optimize='RMSE')
# 047 커스텀 그리드
custom_grid = {
'max_depth': [3, 5, 7, 10, 15],
'min_samples_split': [2, 5, 10, 20],
'min_samples_leaf': [1, 2, 5, 10]
}
tuned_dt = tune_model(dt, custom_grid=custom_grid, optimize='RMSE')
결정 트리의 한계: 계단 함수
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
from sklearn.linear_model import LinearRegression
# 047 선형 관계 데이터
np.random.seed(42)
X = np.random.rand(100, 1) * 10
y = 2 * X.ravel() + 3 + np.random.randn(100) * 2
# 047 모델 학습
dt = DecisionTreeRegressor(max_depth=4)
lr = LinearRegression()
dt.fit(X, y)
lr.fit(X, y)
# 047 예측
X_test = np.linspace(0, 10, 100).reshape(-1, 1)
plt.figure(figsize=(10, 6))
plt.scatter(X, y, alpha=0.5, label='Data')
plt.plot(X_test, dt.predict(X_test), 'r-', linewidth=2, label='Decision Tree')
plt.plot(X_test, lr.predict(X_test), 'g--', linewidth=2, label='Linear Regression')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Decision Tree vs Linear Regression')
plt.legend()
plt.savefig('dt_vs_lr.png', dpi=150)
# 047 결정 트리는 계단 함수 형태로 예측
# 047 선형 관계에서는 선형 회귀가 더 적합
장단점
장점:
- 비선형 관계 포착
- 해석 용이 (규칙으로 변환)
- 스케일링 불필요
- 특성 중요도 제공
단점:
- 과적합 경향
- 불안정 (데이터 변화에 민감)
- 외삽 불가 (학습 범위 밖 예측 한계)
- 계단 함수 형태의 예측
언제 사용하나?
# 1. 해석이 필요한 경우
# 047 의사결정 규칙으로 변환 가능
# 2. 비선형 관계
# 047 선형 모델로 부족할 때
# 3. 앙상블의 기반
# 047 랜덤 포레스트, XGBoost의 기초
# 4. 빠른 프로토타이핑
# 047 데이터 특성 파악
정리
- 결정 트리 회귀는 리프 노드에서 평균값 예측
- max_depth로 과적합 조절
- 비선형 관계를 포착하지만 계단 함수 형태
- 외삽 불가 (학습 범위 밖 예측 한계)
- 앙상블(랜덤 포레스트, XGBoost)의 기반
다음 글 예고
다음 글에서는 랜덤 포레스트 회귀 상세를 다룹니다.
PyCaret 머신러닝 마스터 시리즈 #047