RyanNerd
라덕'Story
RyanNerd
  • 분류 전체보기 (117)
    • Study Note (80)
      • Python (3)
      • R (1)
      • Airflow (7)
      • 통계 (26)
      • Machine Learning (16)
      • Streamlit (9)
      • Django (1)
      • Deep Learning (12)
      • dbt (2)
      • SQL (3)
    • 빅데이터분석기사 (1)
      • 필기 (1)
    • Programmers (28)
      • Python (13)
      • SQL (15)
    • Project (3)
      • Django (3)
    • Mac (2)

블로그 메뉴

  • NaverBlog
  • 홈

최근 글

전체 방문자
오늘
어제
hELLO · Designed By 정상우.
RyanNerd

라덕'Story

응급실 예측 2편: 로그의 마법과 5대 회귀 모델 총출동 (Linear부터 XGBoost까지)
Study Note/Machine Learning

응급실 예측 2편: 로그의 마법과 5대 회귀 모델 총출동 (Linear부터 XGBoost까지)

2025. 12. 24. 16:49

RMSLE(로그 오차)가 의료 데이터(응급실 예측)에서 왜 중요한지 배웠습니다. 오늘은 이론을 넘어, "로그 변환(Log Transform)"을 실제 코드에 어떻게 녹이는지, 그리고 5가지 대표 회귀 모델들이 이 데이터를 어떻게 다루는지 직접 대결을 붙여보겠습니다.

 

1. Model Evaluation의 핵심: 로그와 지수의 '역함수' 관계

모델을 학습시키기 전, 가장 먼저 해야 할 일은 데이터를 "학습하기 좋은 모양"으로 만드는 것입니다.

환자 수 데이터는 보통 0명에 몰려있고 가끔 폭증하는(Skewed) 형태입니다. 이를 펴주기 위해 로그를 씁니다.

  • 들어갈 땐 (Log): np.log1p(y) $\rightarrow$ 데이터를 정규분포처럼 펴줌 + RMSLE 최적화
  • 나올 땐 (Exp): np.expm1(pred) $\rightarrow$ 예측값을 다시 실제 '명' 단위로 복구

 

주의: log의 역함수는 exp입니다. 들어갈 때 로그를 썼다면, 나올 때 반드시 지수(exp)로 되돌려야(Inverse Transform) 원래 값이 됩니다. 안 그러면 "내일 환자가 3.5명 옵니다(실제론 32명)"라는 엉뚱한 보고를 하게 됩니다.

 

2. 데이터 준비: 응급실의 시간을 쪼개다

먼저 가상의 응급실 데이터를 생성하고, 시간 변수를 추출합니다.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

# 1. 가상의 응급실 데이터 생성
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)

# 환자 수 생성 (시간대별 패턴 + 노이즈)
# 1) 기본 패턴: 심야(0~5시)와 오전(9~11시)에 많음
# 2) 주말 효과: 주말엔 환자가 조금 더 많음
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']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

print(f"데이터 준비 완료: {X_train.shape}")

 

3. 모델 대격돌: 5대 회귀 모델 비교

이제 5가지 모델을 하나씩 돌려보며 특징을 알아봅니다. 모든 과정에 Log -> Fit -> Predict -> Exp 파이프라인이 적용됩니다.

① 평가 함수 정의 (RMSLE)

from sklearn.metrics import mean_squared_error

def evaluate_model(model_name, y_true, y_pred):
    # RMSLE 계산: 이미 복원된(exp) 값으로 계산
    rmsle = np.sqrt(np.mean((np.log1p(y_true) - np.log1p(y_pred))**2))
    print(f"[{model_name}] RMSLE: {rmsle:.4f}")
    return rmsle

② Linear Regression (선형 회귀) & Lasso (규제)

  • Linear Regression: 가장 기초적인 모델. "시간이 1시간 늘면 환자가 $w$명 는다"는 단순 비례 관계를 가정합니다.
  • Lasso Regression: 선형 회귀에 L1 규제를 건 모델. 불필요한 변수(예: 영향력 없는 '월')의 가중치를 0으로 만들어버립니다. (Feature Selection 효과)
from sklearn.linear_model import LinearRegression, Lasso

# 1. Linear Regression
lr = LinearRegression()
lr.fit(X_train, np.log1p(y_train)) # 로그 변환 학습
pred_lr = np.expm1(lr.predict(X_test)) # 지수 변환 복구
evaluate_model("Linear Regression", y_test, pred_lr)

# 2. Lasso Regression (규제 적용)
lasso = Lasso(alpha=0.01, random_state=42)
lasso.fit(X_train, np.log1p(y_train))
pred_lasso = np.expm1(lasso.predict(X_test))
evaluate_model("Lasso Regression ", y_test, pred_lasso)

 

③ Random Forest (랜덤 포레스트)

  • 특징: 여러 개의 결정 트리(Decision Tree)가 투표하는 방식.
  • 의료 적용: 선형 모델과 달리, "오전 9시엔 급증했다가 점심엔 줄어드는" 비선형적인 패턴을 아주 잘 잡아냅니다.
from sklearn.ensemble import RandomForestRegressor

# 3. Random Forest
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_train, np.log1p(y_train))
pred_rf = np.expm1(rf.predict(X_test))
evaluate_model("Random Forest    ", y_test, pred_rf)

④ Boosting 형제들: XGBoost & Gradient Boosting

  • Gradient Boosting: 이전 트리가 틀린 오차를 다음 트리가 고쳐나가는 방식. (조금씩 정교해짐)
  • XGBoost: Gradient Boosting의 속도와 성능을 획기적으로 개선한 모델. 캐글(Kaggle) 우승 치트키.
  • 의료 적용: 응급실 데이터처럼 갑자기 튀는 아웃라이어나 미세한 패턴까지 놓치지 않고 학습합니다.
from xgboost import XGBRegressor
from sklearn.ensemble import GradientBoostingRegressor

# 4. Gradient Boosting
gb = GradientBoostingRegressor(n_estimators=100, random_state=42)
gb.fit(X_train, np.log1p(y_train))
pred_gb = np.expm1(gb.predict(X_test))
evaluate_model("Gradient Boosting", y_test, pred_gb)

# 5. XGBoost
xgb = XGBRegressor(n_estimators=100, random_state=42)
xgb.fit(X_train, np.log1p(y_train))
pred_xgb = np.expm1(xgb.predict(X_test))
evaluate_model("XGBoost          ", y_test, pred_xgb)

[최종 결과 분석] 5대 모델 대격돌: 과연 승자는?

실제 데이터를 통해 5가지 회귀 모델을 돌려본 결과, RMSLE(로그 오차) 점수표가 나왔습니다. 점수가 낮을수록(0에 가까울수록) 예측이 정확하다는 뜻입니다.

 

순위 모델 RMSLE 점수 비고
1 Graident Boosting 0.2066 압도적 성능
2 Random Foreest 0.2434 안정적인 상위권
3 XGBoost 0.2443 Random Forest와 유사
4 Linear Regression 0.2517 단순 선형
5 Lasso Regression 0.2559 규제 적용

 

Analyst's Insight: 결과 속에 숨겨진 3가지 의미

1. "응급실은 직선이 아니다" (비선형 모델의 승리)

  • Tree 기반 모델(GBM, RF, XGB) vs 선형 모델(Linear, Lasso)
    • 결과를 보면 트리 기반 모델들(0.20~0.24)이 선형 모델들(0.25대)보다 확실히 성능이 좋습니다.
    • 의료적 해석: 응급실 환자 수는 "시간이 흐른다고 일정하게 늘어나는 것(선형)"이 아닙니다. 오전 9시에 확 몰렸다가, 점심에 빠지고, 저녁에 다시 늘어나는 복잡한 곡선(비선형) 패턴을 그립니다. 선형 회귀는 이 '출렁임'을 따라가지 못해 점수가 낮게 나온 것입니다.

2. 오늘의 MVP는 'Gradient Boosting'

  • RMSLE 0.2066이라는 놀라운 수치로 1위를 차지했습니다. 2위 그룹(0.24대)과도 격차가 꽤 큽니다.
  • 의료적 해석: 이 모델은 이전 트리가 실수한 오차(잔차)를 다음 트리가 집중적으로 고치는 방식입니다. 응급실 데이터에 섞인 불규칙한 노이즈(갑작스러운 사고 등)를 가장 예민하게 잘 학습했다는 뜻입니다. 현업에 배포한다면 이 모델을 선택해야 합니다.

3. XGBoost가 항상 만능은 아니다?

  • 보통 캐글의 제왕이라 불리는 XGBoost(0.2443)가 이번에는 Random Forest(0.2434)나 Gradient Boosting보다 살짝 낮은 점수를 기록했습니다.
  • 이유: XGBoost는 데이터가 아주 많거나(Big Data), 하이퍼파라미터를 섬세하게 튜닝했을 때 진가를 발휘합니다. 기본 설정(Default) 상태이거나 데이터 규모에 따라서는 가볍고 강력한 Gradient Boosting이 더 나을 수도 있습니다.
  • 교훈: "유명한 모델이라고 무조건 믿지 말고, 내 데이터로 직접 테스트(Model Selection) 해봐야 한다"는 분석가의 철칙을 다시 한번 확인했습니다.

단순한 선형 예측보다는 시간의 흐름과 패턴을 읽을 줄 아는 'Gradient Boosting' 모델을 사용하여, 병상 가동 계획을 세우는 것이 가장 효율적입니다.

'Study Note > Machine Learning' 카테고리의 다른 글

정답 없는 환자 데이터에서 그룹 찾기: 군집화(Clustering) 알고리즘 완전 정복  (0) 2025.12.29
의료 AI의 협진 시스템: Random Forest와 XGBoost 섞어 쓰기 (Blending)  (0) 2025.12.29
응급실 예측, 디테일의 차이: Metric 정의부터 타겟 분리(Target Splitting)까지  (0) 2025.12.23
응급실은 언제 붐빌까? : 시계열 회귀, 로그(Log)의 마법, 그리고 4대 평가지표  (0) 2025.12.23
수치 예측의 정석과 과적합을 막는 방패: 회귀(Regression)와 규제(Regularization) 정복하기  (0) 2025.12.22
    'Study Note/Machine Learning' 카테고리의 다른 글
    • 정답 없는 환자 데이터에서 그룹 찾기: 군집화(Clustering) 알고리즘 완전 정복
    • 의료 AI의 협진 시스템: Random Forest와 XGBoost 섞어 쓰기 (Blending)
    • 응급실 예측, 디테일의 차이: Metric 정의부터 타겟 분리(Target Splitting)까지
    • 응급실은 언제 붐빌까? : 시계열 회귀, 로그(Log)의 마법, 그리고 4대 평가지표
    RyanNerd
    RyanNerd
    라이언 덕후의 일상 스토리~

    티스토리툴바