의사 선생님들도 진단이 어려울 때 협진(Consultation)을 하죠? 머신러닝도 마찬가지입니다.
- Random Forest: 전체적인 숲을 보며 안정적인 예측을 잘합니다. (과적합 방지)
- XGBoost: 틀린 문제(오차)를 집요하게 파고들어 디테일을 잡습니다. (높은 정확도)
이 둘을 2:8 또는 5:5 비율로 섞으면, 안정적이면서도 예리한 최상의 예측 모델이 탄생합니다.
1. 데이터 준비: 가상의 응급실 데이터
먼저, 두 모델이 학습할 데이터를 준비합니다. (이전과 동일한 시계열 회귀 데이터)
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
# 1. 가상의 응급실 데이터 생성 (2000시간)
np.random.seed(42)
data_size = 2000
dates = pd.date_range(start='2024-01-01', periods=data_size, freq='h')
df_er = pd.DataFrame({'datetime': dates})
# Feature Engineering
df_er['hour'] = df_er['datetime'].dt.hour
df_er['dayofweek'] = df_er['datetime'].dt.dayofweek
df_er['month'] = df_er['datetime'].dt.month
df_er['is_weekend'] = (df_er['dayofweek'] >= 5).astype(int)
# Target 생성 (환자 수)
# 복잡한 패턴: 시간대별 파동 + 주말 효과 + 랜덤 노이즈
df_er['patient_count'] = 10 + \
5 * np.sin(df_er['hour'] / 24 * 2 * np.pi) + \
3 * df_er['is_weekend'] + \
np.random.randint(0, 10, data_size)
# 학습/테스트 분리
X = df_er[['hour', 'dayofweek', 'month', 'is_weekend']]
y = df_er['patient_count']
# 타겟 로그 변환 (RMSLE 최적화 필수!)
y_log = np.log1p(y)
X_train, X_test, y_train_log, y_test_log = train_test_split(X, y_log, test_size=0.2, random_state=42)
2. 모델 학습: 각자 도생 (따로 학습하기)
두 모델을 각각 최적의 상태로 학습시킵니다. 여기서는 편의상 기본 파라미터를 사용하지만, 실전에서는 GridSearchCV로 튜닝된 파라미터를 씁니다.
from sklearn.ensemble import RandomForestRegressor
from xgboost import XGBRegressor
# --- 모델 1: Random Forest (안정성 담당) ---
rf_model = RandomForestRegressor(n_estimators=100, random_state=42)
rf_model.fit(X_train, y_train_log)
# --- 모델 2: XGBoost (정확도 담당) ---
xgb_model = XGBRegressor(n_estimators=100, learning_rate=0.1, random_state=42)
xgb_model.fit(X_train, y_train_log)
print("두 모델 학습 완료!")
3. [핵심] 모델 블렌딩 (Weighted Blending)
이제 두 모델의 예측값을 가중 평균(Weighted Average)으로 합칩니다. 노트북 파일에서는 0.2 * RF + 0.8 * XGB 비율을 사용했습니다. 성능이 더 좋은 모델(XGB)에 더 많은 신뢰를 주는 전략입니다.
# 1. 각자 예측 (아직 로그 상태임)
pred_log_rf = rf_model.predict(X_test)
pred_log_xgb = xgb_model.predict(X_test)
# 2. 블렌딩 (Ensemble) - 협진 결과 도출
# XGBoost 성능이 보통 더 좋으므로 80% 비중을 둡니다.
# 상황에 따라 0.5 : 0.5 로 섞기도 합니다.
pred_log_blend = (0.2 * pred_log_rf) + (0.8 * pred_log_xgb)
# 3. 지수 변환 (원래 환자 수 단위로 복구)
final_pred = np.expm1(pred_log_blend)
# 비교용: 단일 모델 결과 복구
final_pred_rf = np.expm1(pred_log_rf)
final_pred_xgb = np.expm1(pred_log_xgb)
4. 성능 평가: 뭉치면 살고 흩어지면 죽는다
실제로 섞었을 때 점수가 더 좋아지는지 확인해 봅시다.
from sklearn.metrics import mean_squared_error
def get_rmsle_score(y_true, y_pred):
return np.sqrt(np.mean((np.log1p(y_true) - np.log1p(y_pred))**2))
# 실제 정답 복구
y_test_actual = np.expm1(y_test_log)
# 점수 계산
score_rf = get_rmsle_score(y_test_actual, final_pred_rf)
score_xgb = get_rmsle_score(y_test_actual, final_pred_xgb)
score_blend = get_rmsle_score(y_test_actual, final_pred)
print(f"Random Forest 단독: {score_rf:.4f}")
print(f"XGBoost 단독 : {score_xgb:.4f}")
print(f"Blended (2:8) : {score_blend:.4f}")

앙상블의 역설: 무조건 섞는 게 정답일까?
이미지 속 RMSLE 점수(낮을수록 좋음)를 순위대로 나열해보면 다음과 같습니다.
| 순위 | 모델 | 점수 |
| 1 | XGBoost | 0.2222 |
| 2 | Blended | 0.2251 |
| 3 | Random Forest | 0.2434 |
왜 '블렌딩'이 1등을 못 했을까?
1. "압도적인 에이스(XGBoost)의 존재"
- 이번 데이터(가상의 응급실 데이터)에서는 XGBoost(0.2222)가 Random Forest(0.2434)보다 패턴을 월등히 잘 찾았습니다.
- 격차가 꽤 크다 보니, 성능이 상대적으로 떨어지는 Random Forest의 의견을 20% 섞은 것이 오히려 평균 점수를 깎아먹는 결과(0.2251)를 초래했습니다.
2. 그렇다면 블렌딩은 실패한 것인가? (Stability vs Accuracy)
- 아닙니다. 비록 점수는 0.0029점 떨어졌지만, 안정성(Stability)을 얻었을 가능성이 큽니다.
- 머신러닝에서 단일 모델(XGBoost)은 가끔 특정 데이터에 과하게 맞춰지는 과적합(Overfitting) 위험이 있습니다.
- 블렌딩 모델은 성능을 아주 조금 희생한 대신, XGBoost가 혹시라도 저지를 수 있는 '독단적인 실수'를 Random Forest가 견제해주는 안전장치 역할을 합니다.
3. 실무에서의 대응 전략 (Action Plan)
이런 결과가 나오면 분석가는 다음 두 가지를 시도해야 합니다.
- 가중치 조절: Random Forest의 비중을 줄여봅니다. (2:8 $\rightarrow$ 1:9 또는 0.5 : 9.5)
- 모델 튜닝: Random Forest가 제 몫을 못 하고 있으므로, 파라미터를 튜닝해서 성능을 XGBoost 수준으로 끌어올린 뒤 다시 섞습니다.
왜 섞으면 더 좋을까?
- 상호 보완: Random Forest는 데이터의 노이즈(튀는 값)를 무시하려는 성향이 있고, XGBoost는 노이즈까지 패턴으로 잡으려는 성향이 있습니다. 둘을 섞으면 "너무 둔하지도, 너무 예민하지도 않은" 중용의 미덕을 갖추게 됩니다.
- 리스크 분산: 주식 포트폴리오처럼, 하나의 모델에만 의존하는 것보다 여러 모델의 의견을 듣는 것이 대형 예측 실패(과소평가 등)를 막는 안전장치가 됩니다.
'Study Note > Machine Learning' 카테고리의 다른 글
| 라벨이 없는 환자 데이터에서 '위험군' 찾기: 군집화(Clustering) 알고리즘 4종 정복 (1) | 2025.12.29 |
|---|---|
| 정답 없는 환자 데이터에서 그룹 찾기: 군집화(Clustering) 알고리즘 완전 정복 (0) | 2025.12.29 |
| 응급실 예측 2편: 로그의 마법과 5대 회귀 모델 총출동 (Linear부터 XGBoost까지) (0) | 2025.12.24 |
| 응급실 예측, 디테일의 차이: Metric 정의부터 타겟 분리(Target Splitting)까지 (0) | 2025.12.23 |
| 응급실은 언제 붐빌까? : 시계열 회귀, 로그(Log)의 마법, 그리고 4대 평가지표 (0) | 2025.12.23 |