프로젝트 목록으로

ML Project

리조트 F&B 수요 예측 모델링

메뉴 단위 주간 수요 예측을 위한 Hurdle Model 기반 ML 프로젝트

리조트 식음업장의 메뉴 단위 주간 수요를 예측하기 위해
Zero-Inflated 데이터 특성을 분석하고,
Hurdle Model 기반 예측 구조를 설계한 팀 프로젝트입니다.

팀: 허들허들팀원: 5명역할: 데이터 분석 및 모델링AWS AI School 1기 내 SMAPE 1위

Tech Skills

PythonPandasNumPyLightGBM

Project Summary

판매량 0이 반복되는 운영 데이터를 분석해, 메뉴 단위 주간 수요 예측 문제를 Hurdle Model 기반 구조로 재정의했습니다.

Problem

판매량 0이 많은 수요 데이터

메뉴별 판매량이 자주 0으로 나타나 단순 회귀 모델이 실제 수요 변동을 충분히 따라가기 어려웠습니다.

Approach

예측 문제를 두 단계로 분리

먼저 판매 발생 여부를 예측하고, 판매가 발생한 경우의 수량을 별도로 예측하는 Hurdle Model 구조로 설계했습니다.

Result

SMAPE 0.4598

Weather ON Hurdle Model이 가장 낮은 SMAPE를 기록했고, AWS AI School 1기 내 1위 성과로 이어졌습니다.

EDA: Zero-Inflated 데이터 문제 발견

판매량 0이 얼마나 자주, 얼마나 오래 반복되는지 확인하고 단일 회귀 모델의 예측 한계와 비교했습니다. 이를 바탕으로 수요 예측 문제를 판매 발생 여부와 발생 시 판매량을 나누어 예측하는 구조로 재정의했습니다.

Observation 01

판매량 0이 예외가 아니라 구조적 패턴

평균

52.6%

중앙값

56.4%

절반 이상 0인 메뉴

109개

Zero Sales Ratio Distribution

What I saw

메뉴별 Zero Sales Ratio의 평균과 중앙값이 모두 50%를 넘었습니다. 판매량 0은 일부 메뉴의 이상치가 아니라 데이터 전반에 반복되는 운영 패턴으로 보였습니다.

So I decided

0을 제거하거나 평균으로 메우지 않고, 판매 발생 여부 자체를 별도의 예측 대상으로 분리했습니다.

Observation 02

무판매가 하루 단위 이벤트로 끝나지 않음

7일 이상 연속 무판매

1,030개

분석 관점

상태 지속성

Consecutive Zero Sales Days

What I saw

무판매가 하루 단위로 흩어진 것이 아니라 여러 날 연속되는 구간이 많았습니다. 이는 메뉴가 일시적으로 팔리지 않는 수준을 넘어 활성/비활성 상태가 이어질 수 있음을 보여줍니다.

So I decided

최근 연속 무판매 일수와 최근 판매 발생 비율을 Operational Feature로 추가했습니다.

두 관찰을 바탕으로 모델링 구조 결정

Modeling Decision

단일 회귀보다 2단계 예측 구조가 적합

관찰된 한계

평균 수렴

선택한 구조

Hurdle Model

What I saw

단일 회귀 모델은 실제 판매량의 분산을 충분히 따라가지 못하고 평균 근처로 예측이 눌렸습니다. 무판매와 고수요를 하나의 연속값으로만 설명하기 어려웠습니다.

So I decided

판매 발생 여부를 먼저 분류하고, 판매가 발생한 경우의 수량만 별도 회귀로 예측하는 2단계 구조로 문제를 재정의했습니다.

Single Regression Model Limitation

Data Preprocessing & Feature Engineering

전처리의 목표는 데이터를 깨끗하게 만드는 데서 끝나지 않고, 메뉴별 판매 패턴을 모델이 읽을 수 있는 신호로 바꾸는 것이었습니다. 각 피처 그룹은 EDA에서 확인한 수요 변동, 주기성, 무판매 지속성을 반영하도록 설계했습니다.

Phase 01

Data Preprocessing

날짜와 메뉴 기준이 흔들리면 Lag/Rolling 피처가 틀어지기 때문에, 먼저 예측 가능한 시계열 테이블로 정리했습니다.

날짜 정렬
메뉴 단위 시계열 구성
결측 처리
매출수량 타입 변환

Phase 02

Feature Engineering

전처리된 시계열 위에 달력, 과거 판매 이력, 날씨, 무판매 지속성을 나타내는 피처를 구성했습니다.

Calendar Features

Features

요일, 월, 공휴일, 공휴일 전후, 성수기 여부

Why it matters

식음업장 수요는 주말, 휴일, 성수기처럼 반복되는 달력 패턴의 영향을 받기 때문에 기본 수요 리듬을 표현했습니다.

Time Series Features

Features

Lag 1/7/14/28, Rolling Mean, Rolling Std

Why it matters

최근 판매량과 주간 반복 패턴을 반영해, 메뉴별로 평소 어느 정도 팔렸는지와 변동성이 큰지를 모델이 볼 수 있게 했습니다.

Weather Features

Features

평균기온, 최저기온, 최고기온, 일교차, 강수량, 강수 여부

Why it matters

날씨가 방문객 행동과 메뉴 선택에 영향을 줄 수 있다고 보고, Weather ON/OFF 실험으로 실제 설명력을 비교했습니다.

Operational Features

Features

연속 무판매 일수, 최근 판매 발생 비율, 장기 무판매 추정 플래그

Why it matters

EDA에서 확인한 무판매 지속성을 모델에 전달하기 위해, 메뉴가 최근에 활성 상태였는지 비활성 상태였는지를 나타내는 피처를 추가했습니다.

Model Design: Hurdle Model

EDA에서 확인한 핵심은 판매량 0과 실제 판매량 규모가 서로 다른 성격의 문제라는 점이었습니다. 그래서 판매 발생 여부를 먼저 판단하고, 판매가 발생할 때의 수량만 별도로 예측하는 구조로 설계했습니다.

Structure

입력 피처
판매 발생 여부 예측
발생 시 판매량 예측
Soft Gating으로 결합
최종 예측값

1단계

판매가 발생할까?

판매 발생 확률

특정 날짜에 해당 메뉴가 팔릴 가능성이 있는지 먼저 판단했습니다. 판매량 0이 많은 데이터에서는 수량을 바로 예측하기보다, 판매 발생 조건을 먼저 구분하는 편이 더 자연스러웠습니다.

2단계

팔린다면 얼마나 팔릴까?

발생 시 판매량

판매가 발생한 데이터만 따로 보고 판매량 규모를 예측했습니다. 소량 판매와 대량 판매가 섞여 있어, 판매량은 log1p 변환 후 학습하고 다시 원래 단위로 복원했습니다.

결합

두 예측을 어떻게 합칠까?

Soft Gating

판매 발생 확률을 판매량 예측값에 부드럽게 반영했습니다. 확률이 낮다고 바로 0으로 자르지 않아 예측값이 급격히 흔들리는 문제를 줄였습니다.

비교 실험

날씨 변수는 도움이 됐을까?

Weather ON/OFF

날씨 변수를 포함한 예측과 제외한 예측을 비교했습니다. 날씨가 항상 좋은 피처라고 가정하지 않고, 영업장 성격에 따라 다르게 작동하는지 확인했습니다.

Design Point

Zero-Inflated 데이터에서는 팔릴지와 팔린다면 얼마나 팔릴지가 서로 다른 판단입니다. 이 둘을 분리해 단일 회귀 모델의 평균 수렴 문제를 줄이고, 무판매 패턴을 더 자연스럽게 반영했습니다.

Training, Validation & Forecasting Pipeline

학습과 검증은 점수를 한 번 확인하는 과정이 아니라, 실제 예측 상황을 최대한 비슷하게 재현하는 과정으로 설계했습니다. 시간 순서를 유지하고, 7일 예측을 하루씩 생성한 뒤 제출 가능한 형태로 정리했습니다.

01

시간 기준 분리

과거로 학습하고 이후 기간으로 검증

02

모델 학습

판매 발생 여부와 판매량 규모를 분리 학습

03

성능 검증

Weighted SMAPE로 모델별 성능 비교

04

7일 예측

+1일부터 +7일까지 순차 생성

05

후처리

음수 제거, 정수 변환, 제출 형식 정리

검증 방식

Time-based Holdout

평가 기준

Weighted SMAPE

예측 단위

+1일부터 +7일까지

Result

Baseline과 Hurdle Model 실험 결과를 SMAPE 기준으로 비교했습니다.

ModelSMAPE
Baseline (MA7)0.8118
Baseline (Lag7)0.9777
Hurdle Model (Weather OFF)0.4817
Hurdle Model (Weather ON)0.4598
Ensemble (Store-weighted)0.4610

단순 시계열 기반 Baseline은 판매량 0이 많은 데이터 구조를 충분히 반영하지 못했습니다. 반면 Hurdle Model은 판매 발생 여부와 판매량 규모를 분리해 예측함으로써 더 안정적인 성능을 보였습니다.

What I Learned

01

Zero-Inflated 구조 진단 경험

단일 회귀로 예측했더니 예측 표준편차가 15.94로 실제(58.64) 대비 크게 줄었습니다. 매출 0이 56%인 데이터 구조가 원인임을 분포 분석으로 확인했고, 성능 부진 시 튜닝보다 데이터 구조를 먼저 진단해야 함을 배웠습니다.

02

평가지표에 맞춘 손실함수 설계

SMAPE가 0을 제외하고 비율로 동작하는 점에서 출발해, log1p 변환(왜도 7.729→0.913)에 RMSE를 결합하면 로그 공간의 비율 오차를 최소화함을 정리했습니다. 평가지표 특성에 맞춰 타깃 변환과 손실함수를 설계할 수 있음을 배웠습니다.

03

Hurdle 구조와 Soft Gating 적용

2단계 Hurdle Model을 설계했으나 단순 임계값 분리 시 저빈도 메뉴에서 0 예측이 과하고 예측값이 불연속적으로 튀었습니다. Soft Gating으로 변형해 해결하며, 검증된 구조도 실제 데이터에서 깨지는 지점을 확인하고 수정해야 함을 배웠습니다.