🏡 Housing Prices Competition 문제풀이 - 4. 모델링 및 앙상블
모델링 및 앙상블은 다양한 머신러닝 기법을 활용하여 예측 성능을 극대화하는 과정입니다. 이 글에서는 주택 가격 예측을 위한 모델링 전략을 살펴보고, 여러 모델을 조합하는 앙상블 기법을 통해 보다 안정적이고 정확한 예측을 도출하는 방법을 소개합니다.
📚 시리즈 전체 목차
- 1. 데이터 이해
- 2. 데이터 전처리
- 3. Feature Engineering
- 4. 모델링 및 앙상블
🔎 글 개요
이 글에서는 모델링과 앙상블 기법을 중심으로 주택 가격 예측의 성능을 향상시키는 방법을 다룹니다. 먼저, 훈련 데이터를 안정적으로 학습시키기 위한 데이터 스케일링 기법을 적용하고, 이후 XGBoost, LightGBM, CatBoost 등의 대표적인 부스팅 기반 앙상블 알고리즘을 비교합니다. 마지막으로, 여러 모델의 예측값을 결합하는 블렌딩 기법을 통해 보다 정교한 예측 모델을 구성하는 과정을 소개합니다.
🗂️ 글 내부 목차
1. 데이터 분할
모델의 학습 성능을 평가하기 위해 전체 데이터를 학습용(train)과 평가용(test) 세트로 분할합니다. 첫 번째 글에서 train.csv와 test.csv를 하나로 합친 후 전처리를 진행했기 때문에, 다시 원래의 train과 test 데이터셋으로 구분하는 과정이 필요합니다.
x = X.loc[train.index]
y = y.loc[train.index] # 전글에서 log 변환 해줬던걸 기억해야 합니다!
test = X.loc[test.index]
2. 데이터 크기 조정 (스케일링)
모델의 안정적인 학습을 위해 수치형 변수들에 대해 스케일링을 적용합니다. 특히 RobustScaler를 사용하면 평균과 표준편차가 아닌 중간값(Median)과 IQR(Interquartile Range)을 기준으로 스케일링을 수행하므로, 이상치(Outlier)에 덜 민감하게 데이터를 변환할 수 있습니다.
from sklearn.preprocessing import RobustScaler
cols = x.select_dtypes(np.number).columns # 수치형 열만 선택
transformer = RobustScaler().fit(x[cols]) #학습 데이터 기준으로 RobustScaler 학습
#학습 데이터와 테스트 데이터에 같은 방식으로 변환 적용
x[cols] = transformer.transform(x[cols])
test[cols] = transformer.transform(test[cols])
🔎 왜 스케일링이 필요한가?
많은 머신러닝 모델은 입력 변수의 스케일(값의 범위)에 영향을 받으며, 특히 L1/L2 정규화를 사용하는 선형 모델이나, 경사 하강법(Gradient Descent)을 사용하는 모델들(XGBoost, LightGBM 등)은 변수의 스케일이 클수록 학습이 느려지거나, 성능이 불안정해질 수 있습니다.
이때, 테스트 데이터를 fit()하지 않고 train 기준으로만 transform해야 데이터 누수(Data Leakage)를 방지할 수 있습니다.
3. 앙상블 알고리즘 (모델링)
앙상블(Ensemble) 학습은 여러 개의 모델을 결합하여 예측 성능을 높이는 기법입니다. 각 모델이 개별적으로 예측하는 값에 가중치를 두거나, 예측 결과를 결합하여 최종 예측값을 도출합니다. 앙상블 학습의 주요 목표는 개별 모델들의 분산(Variance)을 줄이고, 편향(Bias)을 개선하는 것입니다.
앙상블 방법에는 다음과 같은 주요 기법들이 있습니다:
- 배깅(Bagging): 여러 개의 모델을 독립적으로 학습시킨 후, 예측 결과를 평균내거나 다수결로 결합합니다. 예: Random Forest.
- 부스팅(Boosting): 약한 모델들을 순차적으로 학습시켜, 이전 모델의 오류를 보완하며 점진적으로 예측 성능을 향상시킵니다. 예: XGBoost, LightGBM, CatBoost.
- 스태킹(Stacking): 여러 다른 모델을 학습시키고, 그 예측을 새로운 데이터로 학습시켜 최종 예측을 도출합니다. 보통 여러 다른 모델들의 결과를 메타 모델을 사용해 결합합니다.
이 글에서는 부스팅 계열의 알고리즘, 특히 XGBoost, LightGBM, CatBoost 등의 주요 부스팅 알고리즘에 중점을 두고 학습합니다.

# 먼저 이 코드를 실행하여 준비하자
from sklearn.metrics import mean_squared_error, mean_absolute_error
from xgboost import XGBRegressor
from sklearn import ensemble
from lightgbm import LGBMRegressor
from sklearn.model_selection import cross_val_score
from catboost import CatBoostRegressor
3.1 데이터 분할
앙상블 모델을 훈련하기 전에, 데이터를 훈련 세트(training set)와 검증 세트(validation set)로 분할해야 합니다. 이 작업을 통해 모델을 훈련시키고, 성능을 평가할 수 있습니다. 데이터는 일반적으로 80%를 훈련 세트로, 나머지 20%를 검증 세트로 사용합니다.
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(x, y, test_size=0.2, random_state=2020)
- X_train, y_train: 훈련 세트의 피처와 타겟 값
- X_val, y_val: 검증 세트의 피처와 타겟 값
3.2 XGBoost
XGBoost는 그래디언트 부스팅 프레임워크 기반으로 성능과 속도가 향상된 알고리즘입니다. 기본 설정과 하이퍼파라미터 튜닝 과정을 소개합니다.
# 기본 XGB 모델( 시간이 오래걸리는게 싫으면 이거만 하면 됩니다! )
# xgb = XGBRegressor(booster='gbtree', learning_rate=0.3, n_estimators=3460,
# max_depth=6, min_child_weight=1, subsample=1,
# gamma=0, reg_alpha=0.001, colsample_bytree=0.7,
# objective='reg:squarederror', reg_lambda=0.001,
# scale_pos_weight=1, seed=2020)
xgb = XGBRegressor(booster='gbtree', objective='reg:squarederror')
# 하이퍼파라미터 튜닝
from sklearn.model_selection import RandomizedSearchCV
param_lst = {
'learning_rate': [0.01, 0.1, 0.15, 0.3, 0.5],
'n_estimators': [100, 500, 1000, 2000, 3000],
'max_depth': [3, 6, 9],
'min_child_weight': [1, 5, 10, 20],
'reg_alpha': [0.001, 0.01, 0.1],
'reg_lambda': [0.001, 0.01, 0.1]
}
xgb_reg = RandomizedSearchCV(estimator=xgb, param_distributions=param_lst,
n_iter=100, scoring='neg_root_mean_squared_error',
cv=5)
xgb_search = xgb_reg.fit(X_train, y_train)
best_param = xgb_search.best_params_
xgb = XGBRegressor(**best_param)
1. 기본 모델 정의
XGBoost의 기본 회귀 모델을 설정합니다. 여기서는 booster='gbtree'를 사용하여 트리 기반 부스팅 모델을 선택합니다.
objective='reg:squarederror'는 XGBoost 모델에서 회귀 문제를 풀 때 사용하는 손실 함수(loss function)를 지정하는 부분입니다. 여기서 squarederror는 평균 제곱 오차 (Mean Squared Error, MSE)를 사용하여 모델을 훈련시키겠다는 뜻입니다.
xgb = XGBRegressor(booster='gbtree', objective='reg:squarederror')
2. 하이퍼파라미터 튜닝
모델 성능을 최적화하기 위해 여러 하이퍼파라미터를 랜덤 서치(RandomizedSearchCV)를 사용해 튜닝합니다. 랜덤 서치는 주어진 하이퍼파라미터 공간에서 임의로 조합을 선택하여 최적의 파라미터를 찾는 방법입니다.
from sklearn.model_selection import RandomizedSearchCV
param_lst = {
'learning_rate': [0.01, 0.1, 0.15, 0.3, 0.5],
'n_estimators': [100, 500, 1000, 2000, 3000],
'max_depth': [3, 6, 9],
'min_child_weight': [1, 5, 10, 20],
'reg_alpha': [0.001, 0.01, 0.1],
'reg_lambda': [0.001, 0.01, 0.1]
}
xgb_reg = RandomizedSearchCV(estimator=xgb, param_distributions=param_lst,
n_iter=100, scoring='neg_root_mean_squared_error',
cv=5)
xgb_search = xgb_reg.fit(X_train, y_train)
3. 최적 하이퍼파라미터 적용
랜덤 서치 후, 최적의 하이퍼파라미터를 선택하여 모델을 재정의합니다. best_params_를 통해 최적의 하이퍼파라미터를 얻고, 이를 기반으로 모델을 업데이트합니다.
best_param = xgb_search.best_params_
xgb = XGBRegressor(**best_param)
3.3 LightGBM
LightGBM은 Microsoft에서 개발한 고속 그래디언트 부스팅 프레임워크로, 히스토그램 기반 알고리즘을 사용해 학습 속도와 메모리 효율을 개선한다 합니다. 특히 대규모 데이터와 고속 학습에 강점을 가지고 있으며, 메모리 사용과 학습 속도에서 다른 부스팅 모델들보다 효율적입니다.
lgbm = LGBMRegressor(boosting_type='gbdt', objective='regression', max_depth=-1,
lambda_l1=0.0001, lambda_l2=0, learning_rate=0.1,
n_estimators=100, max_bin=200, min_child_samples=20,
bagging_fraction=0.75, bagging_freq=5,
bagging_seed=7, feature_fraction=0.8,
feature_fraction_seed=7, verbose=-1)
# 하이퍼파라미터 튜닝
param_lst = {
'max_depth': [2, 5, 8, 10],
'learning_rate': [0.001, 0.01, 0.1, 0.2],
'n_estimators': [100, 300, 500, 1000, 1500],
'lambda_l1': [0.0001, 0.001, 0.01],
'lambda_l2': [0, 0.0001, 0.001, 0.01],
'feature_fraction': [0.4, 0.6, 0.8],
'min_child_samples': [5, 10, 20, 25]
}
lightgbm = RandomizedSearchCV(estimator=lgbm, param_distributions=param_lst,
n_iter=100, scoring='neg_root_mean_squared_error',
cv=5)
lightgbm_search = lightgbm.fit(X_train, y_train)
best_param = lightgbm_search.best_params_
lgbm = LGBMRegressor(**best_param)
lgbm = LGBMRegressor(boosting_type='gbdt', objective='regression', ...)
- boosting_type='gbdt': 기본 부스팅 방식인 Gradient Boosting Decision Tree (GBDT) 방식을 사용합니다. 이는 트리 기반 알고리즘으로 여러 약한 학습기(weak learner)를 결합해 강력한 모델을 만듭니다.
- objective='regression': 회귀 문제를 다룰 때 사용됩니다. 이 설정은 모델이 회귀를 위한 손실 함수 (예: MSE 또는 RMSE)를 사용하도록 합니다.
3.4 CatBoost
CatBoost는 범주형 피처 처리에 강점을 가진 Yandex 개발 그래디언트 부스팅 프레임워크입니다. 다른 부스팅 모델들처럼 데이터를 처리하기 위해 별도의 원-핫 인코딩을 하지 않고도 범주형 피처를 직접 사용할 수 있어, 데이터 전처리 과정이 간소화되는 장점이 있습니다. Gradient Boosting을 기반으로 하며, 특히 범주형 변수의 처리에 있어 뛰어난 성능을 보입니다.
cb = CatBoostRegressor(loss_function='RMSE', logging_level='Silent')
# 하이퍼파라미터 튜닝
param_lst = {
'n_estimators': [100, 300, 500, 1000, 1300, 1600],
'learning_rate': [0.0001, 0.001, 0.01, 0.1],
'l2_leaf_reg': [0.001, 0.01, 0.1],
'random_strength': [0.25, 0.5, 1],
'max_depth': [3, 6, 9],
'min_child_samples': [2, 5, 10, 15, 20],
'rsm': [0.5, 0.7, 0.9]
}
catboost = RandomizedSearchCV(estimator=cb, param_distributions=param_lst,
n_iter=100, scoring='neg_root_mean_squared_error',
cv=5)
catboost_search = catboost.fit(X_train, y_train)
best_param = catboost_search.best_params_
cb = CatBoostRegressor(logging_level='Silent', **best_param)
cb = CatBoostRegressor(loss_function='RMSE', logging_level='Silent')
- loss_function='RMSE': RMSE (Root Mean Squared Error)를 손실 함수로 사용하여 모델을 학습합니다.
- logging_level='Silent': 모델 훈련 중의 로그 출력을 제한하여, 학습 과정에서 불필요한 출력이 나오지 않도록 설정합니다.
3.5 모델 평가
각 모델을 학습 및 검증 세트에서 평가하고, MAE (Mean Absolute Error), RMSE (Root Mean Squared Error), Cross-Validation (CV) Score를 이용하여 모델들을 평가합니다.
def mean_cross_val(model, X, y):
score = cross_val_score(model, X, y, cv=5)
return score.mean()
# CatBoost 평가
cb.fit(X_train, y_train)
preds_cb = cb.predict(X_val)
mae_cb = mean_absolute_error(y_val, preds_cb)
rmse_cb = np.sqrt(mean_squared_error(y_val, preds_cb))
cv_cb = mean_cross_val(cb, x, y)
# XGBoost 평가
xgb.fit(X_train, y_train)
preds_xgb = xgb.predict(X_val)
mae_xgb = mean_absolute_error(y_val, preds_xgb)
rmse_xgb = np.sqrt(mean_squared_error(y_val, preds_xgb))
cv_xgb = mean_cross_val(xgb, x, y)
# LightGBM 평가
lgbm.fit(X_train, y_train)
preds_lgbm = lgbm.predict(X_val)
mae_lgbm = mean_absolute_error(y_val, preds_lgbm)
rmse_lgbm = np.sqrt(mean_squared_error(y_val, preds_lgbm))
cv_lgbm = mean_cross_val(lgbm, x, y)
1. MAE (Mean Absolute Error)
MAE는 예측값과 실제값 간의 절대적인 차이를 평균한 값입니다. 수식으로는 다음과 같습니다.

- 장점: MAE는 예측값과 실제값 간의 차이를 직관적으로 측정할 수 있는 간단한 지표입니다. 큰 오차에 대해 선형적으로 반응하기 때문에 이상치에 덜 민감합니다.
- 단점: MAE는 큰 오차를 강조하지 않으므로, 이상치에 대한 모델의 민감도를 반영하지 못합니다.
2. RMSE (Root Mean Squared Error)
RMSE는 예측값과 실제값 간의 차이를 제곱하여 평균을 구하고, 그 값을 제곱근한 값입니다. 수식은 다음과 같습니다.

- 장점: RMSE는 예측 오차의 크기를 제곱하여 강조하므로, 큰 오차가 있을 때 모델이 이를 더 신경 쓰게 만듭니다. 이상치에 민감하게 반응합니다.
- 단점: 이상치에 과도하게 민감할 수 있습니다.
3. Cross-Validation Score (CV Score)
Cross-Validation은 데이터를 여러 번 나누어 모델을 학습하고 평가하는 방법으로, 모델의 성능을 더 안정적이고 일반화된 방식으로 평가할 수 있습니다. 여기서는 5-fold cross-validation(cv=5)을 사용하여 모델을 평가하고, 그 결과의 평균을 구해 CV 점수로 나타냅니다.

- 장점: 모델의 일반화 성능을 평가할 수 있어, 훈련 데이터에 과적합된 모델을 방지할 수 있습니다.
- 단점: 시간이 많이 소요되며, 계산량이 많을 수 있습니다.
model_performances = pd.DataFrame({
"Model": ["XGBoost", "LGBM", "CatBoost"],
"CV(5)": [cv_xgb, cv_lgbm, cv_cb],
"MAE": [mae_xgb, mae_lgbm, mae_cb],
"RMSE": [rmse_xgb, rmse_lgbm, rmse_cb]
})
print("Sorted by RMSE:")
print(model_performances.sort_values(by="RMSE"))
Sorted by Score:
Model CV(5) MAE RMSE Score
2 CatBoost 0.916 0.072 0.103 0.927
0 XGBoost 0.911 0.077 0.109 0.918
1 LGBM 0.910 0.078 0.112 0.915
catboost의 성능이 제일 좋았습니다.
3.6 블렌딩
블렌딩(Blending)은 여러 개의 예측 모델을 결합하여 최종 예측을 도출하는 기법입니다. 각 모델의 예측 결과에 가중치를 부여하여 더 나은 예측 성능을 얻을 수 있도록 합니다. 이 기법은 특히 다양한 모델들이 각기 다른 특성을 가지므로, 여러 모델의 장점을 결합하여 성능을 향상시킬 수 있습니다.
def blend_models_predict(X, b, c, d):
# 각 모델의 예측값에 가중치 b, c, d를 부여하여 최종 예측을 생성합니다.
return (b * xgb.predict(X) + c * lgbm.predict(X) + d * cb.predict(X))
subm = np.exp(blend_models_predict(test, 0.4, 0.3, 0.3))
#np.exp()를 사용하여 로그 변환된 값을 원래의 Scale로 되돌립니다. 이전 feature engineering 글 참조
submission = pd.DataFrame({'Id': test.index, 'SalePrice': subm})
submission.to_csv("../../kaggle/working/submission.csv", index=False)
📚 시리즈 전체 목차
- 1. 데이터 이해
- 2. 데이터 전처리
- 3. Feature Engineering
- 4. 모델링 및 앙상블
→ Housing Prices Competition 정복!