반응형

1. 회귀 트리 기반 모델 개요
앞선 1·2편에서는 선형 회귀 + 규제(Ridge/Lasso) 와
로그 변환, 왜도 보정, 이상치 제거를 통해 성능을 지속적으로 개선했습니다.
이번 3편에서는
👉 비선형 관계를 학습할 수 있는 트리 기반 회귀 모델
👉 여러 모델의 예측을 결합하는 앙상블 전략
👉 최종적으로 Stacking 모델까지 적용합니다.
2. XGBoost / LightGBM 회귀 모델
트리 기반 모델을 사용하기 전 컬럼명 정제
# XGBoost는 특수문자가 포함된 컬럼명을 허용하지 않음
# One-Hot Encoding 과정에서 생성된 [, ], < 문자를 제거/치환
from xgboost import XGBRegressor
X_features.columns = (
X_features.columns
.str.replace('[', '_', regex=False)
.str.replace(']', '_', regex=False)
.str.replace('<', '_', regex=False)
)
# 혹시 중복된 컬럼명이 있다면 제거
X_features = X_features.loc[:, ~X_features.columns.duplicated()]
✔ 왜 필요한가?
- XGBoost 내부는 C++ 기반 → 특수문자 컬럼명에서 에러 발생
- 모델 학습 이전 반드시 정제 필요
XGBoost 회귀 모델 + GridSearchCV
from xgboost import XGBRegressor
from sklearn.model_selection import GridSearchCV
# XGBoost 회귀 모델 정의
xgb_reg = XGBRegressor(
n_estimators=1000, # 트리 개수
learning_rate=0.05, # 학습률
colsample_bytree=0.5, # 피처 샘플링 비율
subsample=0.8, # 데이터 샘플링 비율
objective='reg:squarederror', # 회귀용 손실 함수
random_state=156
)
# 튜닝할 파라미터
xgb_params = {'n_estimators': [1000]}
# GridSearchCV를 이용해 교차검증 기반 성능 평가
best_xgb = print_best_params(xgb_reg, xgb_params)
# 결과 5 폴드시 최적 평균 RMSE : 0.1174
GridSearchCV 공통 함수 (재정의)
def print_best_params(model, params):
grid_model = GridSearchCV(
model,
param_grid=params,
scoring='neg_mean_squared_error',
cv=5
)
# LightGBM/XGBoost 안정성을 위해 numpy array로 변환
grid_model.fit(X_features.values, y_target.values)
rmse = np.sqrt(-grid_model.best_score_)
print(f'5 폴드시 최적 평균 RMSE : {np.round(rmse,4)}')
print(f'최적 파라미터 : {grid_model.best_params_}')
return grid_model.best_estimator_
LightGBM 회귀 모델
from lightgbm import LGBMRegressor
lgbm_params = {'n_estimators':[1000]}
lgbm_reg = LGBMRegressor(
n_estimators=1000,
learning_rate=0.05,
num_leaves=4,
subsample=0.6,
colsample_bytree=0.4,
reg_lambda=10,
n_jobs=-1
)
best_lgbm = print_best_params(lgbm_reg, lgbm_params)
# 결과 : 5 폴드시 최적 평균 RMSE : 0.1159
3. 트리 모델 피처 중요도 분석
# 상위 20개 중요 피처 추출 함수
def get_top_features(model):
ftr_importances_values = model.feature_importances_
ftr_importances = pd.Series(ftr_importances_values, index=X_features.columns)
return ftr_importances.sort_values(ascending=False)[:20]
# XGBoost / LightGBM 피처 중요도 시각화
def visualize_ftr_importances(models):
fig, axs = plt.subplots(figsize=(24,10), nrows=1, ncols=2)
for i_num, model in enumerate(models):
ftr_top20 = get_top_features(model)
axs[i_num].set_title(model.__class__.__name__+' Feature Importances', size=25)
sns.barplot(x=ftr_top20.values, y=ftr_top20.index, ax=axs[i_num])
models = [best_xgb, best_lgbm]
visualize_ftr_importances(models)
✔ 트리 모델은 선형 회귀와 달리 비선형 상호작용을 자동 학습

4. 예측값 혼합 (Blending)
# RMSE 계산 함수
def get_rmse_pred(preds):
for key in preds.keys():
mse = mean_squared_error(y_test , preds[key])
rmse = np.sqrt(mse)
print('{0} 모델의 RMSE: {1}'.format(key, rmse))
# 개별 모델 학습
ridge_reg = Ridge(alpha=8)
ridge_reg.fit(X_train, y_train)
lasso_reg = Lasso(alpha=0.001)
lasso_reg.fit(X_train, y_train)
# 예측
ridge_pred = ridge_reg.predict(X_test)
lasso_pred = lasso_reg.predict(X_test)
# 예측값 가중 평균
pred = 0.4 * ridge_pred + 0.6 * lasso_pred
preds = {
'최종 혼합': pred,
'Ridge': ridge_pred,
'Lasso': lasso_pred
}
get_rmse_pred(preds)
# 결과 : 최종 혼합 RMSE : 0.0993
5. 스태킹(Stacking) 앙상블
스태킹 개념
- 기반 모델(Base Model) 의 예측값을
- 메타 모델(Meta Model) 이 다시 학습
스태킹용 데이터 생성 함수
from sklearn.model_selection import KFold
def get_stacking_base_datasets(model, X_train_n, y_train_n, X_test_n, n_folds ):
kf = KFold(n_splits=n_folds, shuffle=False)
train_fold_pred = np.zeros((X_train_n.shape[0], 1))
test_pred = np.zeros((X_test_n.shape[0], n_folds))
for folder_counter, (train_index, valid_index) in enumerate(kf.split(X_train_n)):
X_tr = X_train_n[train_index]
y_tr = y_train_n[train_index]
X_te = X_train_n[valid_index]
model.fit(X_tr, y_tr)
train_fold_pred[valid_index, :] = model.predict(X_te).reshape(-1,1)
test_pred[:, folder_counter] = model.predict(X_test_n)
return train_fold_pred, np.mean(test_pred, axis=1).reshape(-1,1)
스태킹 데이터 구성
X_train_n = X_train.values
X_test_n = X_test.values
y_train_n = y_train.values
ridge_train, ridge_test = get_stacking_base_datasets(ridge_reg, X_train_n, y_train_n, X_test_n, 5)
lasso_train, lasso_test = get_stacking_base_datasets(lasso_reg, X_train_n, y_train_n, X_test_n, 5)
xgb_train, xgb_test = get_stacking_base_datasets(xgb_reg, X_train_n, y_train_n, X_test_n, 5)
lgbm_train, lgbm_test = get_stacking_base_datasets(lgbm_reg, X_train_n, y_train_n, X_test_n, 5)
# 기반 모델 예측값 결합
Stack_final_X_train = np.concatenate(
(ridge_train, lasso_train, xgb_train, lgbm_train), axis=1
)
Stack_final_X_test = np.concatenate(
(ridge_test, lasso_test, xgb_test, lgbm_test), axis=1
)
메타 모델 학습 및 최종 평가
meta_model_lasso = Lasso(alpha=0.0005)
meta_model_lasso.fit(Stack_final_X_train, y_train)
final = meta_model_lasso.predict(Stack_final_X_test)
rmse = np.sqrt(mean_squared_error(y_test, final))
print('스태킹 회귀 모델의 최종 RMSE 값은:', rmse)
# RMSE : 0.0972
정리 (3편 요약)
| 단계 | RMSE |
| 기본 선형회귀 | ~0.16 |
| 로그 + 튜닝 | ~0.13 |
| 이상치 제거 | ~0.10 |
| 예측 혼합 | ~0.099 |
| 스태킹 앙상블 | 0.097 |
반응형
'Programming' 카테고리의 다른 글
| 차원 축소(Dimension Reduction) 이해와 PCA 실습 (0) | 2026.01.11 |
|---|---|
| 회귀(Regression) 핵심 개념 최종 요약 정리 (0) | 2026.01.09 |
| 캐글 주택가격 예측 프로젝트 (2편) : 교차검증, 하이퍼파라미터 튜닝, 왜도 보정, 이상치 제거를 통한 성능 고도화 (0) | 2026.01.09 |
| 캐글 주택가격 예측 프로젝트 (1편) : 고급 회귀 기법을 위한 데이터 이해와 선형 회귀 모델 분석 (0) | 2026.01.09 |
| Bike Demand 예측 프로젝트 : 회귀 기반 수요 예측 실전 프로젝트 정리 (0) | 2026.01.09 |