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

Study Note/Machine Learning

응급실은 언제 붐빌까? : 시계열 회귀, 로그(Log)의 마법, 그리고 4대 평가지표

2025. 12. 23. 11:08

지금까지 우리는 "환자가 질병이다/아니다"를 분류(Classification)하는 문제에 익숙했습니다.

하지만 병원 운영의 관점에서는 "내일 응급실에 환자가 몇 명이나 올까?" 같은 수치(Quantity)를 예측하는 회귀(Regression) 문제가 더 시급할 때가 많습니다.

오늘은 시계열 데이터의 특성을 활용해 응급실 환자 수를 예측해보고, 점수를 극대화하는 로그 변환(Log Transformation) 기법과 모델의 성적표인 4대 회귀 평가 지표를 파헤쳐 봅니다. 특히 RMSLE가 왜 의료 현장에서 중요한지 직접 코드로 확인해 보겠습니다.

 

1. 데이터의 맥락을 읽다: 시간(Time)의 마법

응급실 데이터는 시간의 흐름 속에 패턴이 숨어 있습니다. 머신러닝 모델에게 2025-12-25 02:00:00이라는 날짜 문자열을 그냥 던져주면 이해하지 못합니다. 이를 자전거 대여량 예측 때처럼 의학적/사회적 의미가 담긴 변수로 쪼개줘야 합니다.

시나리오: 응급실(ER) 내원 환자 예측 데이터

import pandas as pd
import numpy as np

# 가상의 응급실 데이터 생성
dates = pd.date_range(start='2024-01-01', periods=1000, freq='h')
df_er = pd.DataFrame({'datetime': dates})
df_er['patient_count'] = np.random.randint(0, 50, size=1000) # 환자 수

# 1. 시간 변수 분해 (Feature Engineering)
# 모델이 이해할 수 있도록 시간의 특성을 추출합니다.
df_er['year'] = df_er['datetime'].dt.year
df_er['month'] = df_er['datetime'].dt.month   # 계절성 (독감, 식중독 등)
df_er['day'] = df_er['datetime'].dt.day
df_er['hour'] = df_er['datetime'].dt.hour     # 시간대 (심야 취객, 오전 외래 대기)
df_er['dayofweek'] = df_er['datetime'].dt.dayofweek # 요일 (월요병, 주말 의료공백)

print(df_er.head())

Insight: 이렇게 시간을 쪼개면 심야 시간이나 월요일 오전 같은 응급실만의 고유한 패턴을 모델이 학습할 수 있습니다.

 

2. [핵심 테크닉] 점수를 올리는 비기: 로그 변환 (Log Transformation)

대부분의 회귀 모델은 RMSE(오차 제곱)를 줄이려 노력하지만, 우리의 평가 기준이 RMSLE(로그 오차)라면 전략을 바꿔야 합니다. 가장 확실한 방법은 "정답지(Target)를 미리 로그로 바꿔버리는 것"입니다.

① 왜 로그를 씌울까?

  1. 평가 기준 맞춤: 타겟값($y$)에 로그를 씌우고 학습시키면, 모델이 오차를 줄이는 과정이 결과적으로 RMSLE를 줄이는 것과 수학적으로 동일해집니다.
  2. 데이터 분포 정규화: 환자 수 데이터는 보통 왼쪽으로 쏠려있고 오른쪽으로 긴 꼬리(Skewed)를 가집니다. 로그를 씌우면 데이터가 예쁜 정규분포(Bell Shape) 모양으로 펴져서 학습이 잘 됩니다.

② 실전 코드: "로그로 들어갔다가 지수로 나온다"

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

# 1. 학습 전: 타겟값(환자 수)에 로그 씌우기 (Log Transform)
# np.log1p는 log(x+1)을 계산해 0일 때 -무한대 에러를 방지합니다.
y_log = np.log1p(df_er['patient_count'])
X = df_er[['year', 'month', 'day', 'hour', 'dayofweek']]

# 데이터 분리
X_train, X_test, y_train_log, y_test_log = train_test_split(X, y_log, test_size=0.2, random_state=42)

# 2. 모델 학습 (Training)
# 모델은 실제 환자 수가 아니라 '로그 변환된 환자 수'를 학습합니다.
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X_train, y_train_log)

# 3. 예측 (Prediction)
# 이 예측값(pred_log)은 아직 로그 단위입니다. (예: 3.5명 -> 실제로는 약 32명)
pred_log = model.predict(X_test)

# 4. 예측 후: 원래 단위(명)로 되돌리기 (Exponential Transform)
# 로그의 반대인 지수(Exp) 함수로 복원해야 실제 '몇 명'인지 알 수 있습니다.
final_prediction = np.expm1(pred_log)

print(f"로그 예측값 (일부): {pred_log[:3]}")
print(f"실제 복원값 (일부): {final_prediction[:3]}")

 

[실행 결과 해석] 로그의 세계에서 현실로 복귀하기

코드 실행 결과를 보면, "복원(Inverse Transformation)" 과정이 왜 필수적인지 명확히 알 수 있습니다.

  • 로그 예측값 (Log Scale Prediction): [3.26, 3.28, 2.97 ...]
    • 모델이 뱉어낸 날것의 예측값입니다.
    • 이 숫자는 로그($\log$)가 씌워진 상태라 현실적인 의미(환자 수)를 직관적으로 알기 어렵습니다.
    • 만약 이 값을 그대로 보고한다면? **"내일 환자가 3명 옵니다"**라고 보고하게 됩니다. (대참사)
  • 실제 복원값 (Real Scale Prediction): [25.04, 25.62, 18.51 ...]
    • np.expm1 함수를 통해 지수 변환을 거친 진짜 예측값입니다.
    • 로그 값 3.26은 실제로는 약 25명을 의미했습니다. ($e^{3.26} - 1 \approx 25$)
    • 로그 값 2.97은 실제로는 약 18.5명을 의미합니다. 

Insight: 이 결과는 전처리 파이프라인(Log In $\rightarrow$ Exp Out)이 정상적으로 작동했음을 증명합니다. 특히 3.2라는 작은 숫자가 실제로는 25명이라는 큰 차이를 만든다는 것을 기억하세요. 마지막에 지수 변환을 깜빡하면, 응급실 병상을 턱없이 부족하게 준비하는 치명적인 실수를 범하게 됩니다.

 

3. 평가의 척도: 우리는 얼마나 틀렸을까? (4대 지표 총정리)

모델을 만들었으니 채점을 해봐야겠죠? 의료 데이터에서 각 지표가 갖는 의미를 비교해 봅니다.

① MAE (Mean Absolute Error): "가장 직관적인 점수"

  • 공식: 오차의 절댓값 평균
  • 특징: "평균적으로 5명 틀려요."라고 보고하기 좋습니다. 단, 대형 오차를 반영하지 못할 수 있습니다.

② MSE (Mean Squared Error): "큰 실수 용납 못 해"

  • 공식: 오차를 제곱해서 평균
  • 특징: 오차가 클수록 벌점이 기하급수적으로 커집니다. (주로 수학적 계산용)

③ RMSE (Root Mean Squared Error): "표준적인 채점 기준"

  • 공식: MSE에 루트를 씌워 단위 복구
  • 특징: MAE보다 큰 오차(대형 사고)에 민감하게 반응합니다. 가장 무난하게 쓰입니다.

④ RMSLE (Root Mean Squared Log Error): "비율과 과소평가가 중요할 때"

  • 공식: 예측값과 실제값에 로그를 씌운 뒤 RMSE 계산
  • 특징:
    1. 상대적 비율: 100명 중 10명 틀린 것(심각)과 10,000명 중 10명 틀린 것(경미)을 구분합니다.
    2. 과소평가 페널티: 예측값이 실제보다 적을 때(Under-prediction) 더 큰 벌점을 줍니다.

4. [실습] Python으로 4대 지표 구현하기: RMSLE가 과소평가를 싫어하는 이유

직접 코드로 구현하여 MAE와 RMSLE가 같은 오차를 어떻게 다르게 평가하는지 확인해 봅시다. 의료 자원 관리에서 "예측이 빗나가서 환자를 못 받는 상황(과소평가)"이 얼마나 위험한지 알 수 있습니다.

from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np

# RMSLE 함수 정의 (sklearn의 mean_squared_log_error와 동일 로직)
def rmsle(y_true, y_pred):
    return np.sqrt(np.mean((np.log1p(y_true) - np.log1p(y_pred))**2))

# 상황: 실제 환자 100명
y_true = np.array([100])

# 예측 A: 120명 (과대평가 - 병상 남음, 비용 낭비)
y_pred_over = np.array([120])

# 예측 B: 80명 (과소평가 - 병상 부족, 의료 대란)
y_pred_under = np.array([80])


print(f"MAE (과대 예측 120명): {mean_absolute_error(y_true, y_pred_over):.2f}")
print(f"MAE (과소 예측 80명) : {mean_absolute_error(y_true, y_pred_under):.2f}")


print(f"RMSLE (과대 예측 120명): {rmsle(y_true, y_pred_over):.4f}")
print(f"RMSLE (과소 예측 80명) : {rmsle(y_true, y_pred_under):.4f}")

 

[실행 결과 해석]

  • MAE: 둘 다 20.00입니다. 병원장님께 보고할 때는 편하지만, 위험성을 구분하지 못합니다.
  • RMSLE: 과대평가는 0.18, 과소평가는 0.22 정도가 나옵니다. 즉, "환자가 덜 온다고 예측해서 준비를 안 해놓는 실수"에 더 가혹한 벌점을 줍니다.

5. 결론: 데이터 분석가의 통찰력

좋은 모델을 만드는 것은 단순히 알고리즘을 돌리는 것이 아닙니다.

  1. Feature Engineering: datetime을 쪼개 환자의 생활 패턴을 읽어내고,
  2. Transformation: Log 변환으로 데이터 분포를 펴서 학습 효율을 높이며,
  3. Evaluation: "과소평가가 더 위험하다"는 도메인 특성에 맞춰 RMSLE로 검증하는 것.

 

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

응급실 예측 2편: 로그의 마법과 5대 회귀 모델 총출동 (Linear부터 XGBoost까지)  (0) 2025.12.24
응급실 예측, 디테일의 차이: Metric 정의부터 타겟 분리(Target Splitting)까지  (0) 2025.12.23
수치 예측의 정석과 과적합을 막는 방패: 회귀(Regression)와 규제(Regularization) 정복하기  (0) 2025.12.22
정확도(Accuracy)의 함정에서 탈출하기: OOB Score와 ROC-AUC 완벽 해설  (0) 2025.12.22
혼자보다 나은 우리: 보팅(Voting) 앙상블로 예측 성능 극대화하기  (0) 2025.12.22
    'Study Note/Machine Learning' 카테고리의 다른 글
    • 응급실 예측 2편: 로그의 마법과 5대 회귀 모델 총출동 (Linear부터 XGBoost까지)
    • 응급실 예측, 디테일의 차이: Metric 정의부터 타겟 분리(Target Splitting)까지
    • 수치 예측의 정석과 과적합을 막는 방패: 회귀(Regression)와 규제(Regularization) 정복하기
    • 정확도(Accuracy)의 함정에서 탈출하기: OOB Score와 ROC-AUC 완벽 해설
    RyanNerd
    RyanNerd
    라이언 덕후의 일상 스토리~

    티스토리툴바