
수요 예측에서의 절단 문제 ④ 구현 편 · 기존 상품 ─ EM Unconstraining과 NumPyro를 이용한 베이즈 추론
요약
수요 예측 시 재고나 발주량 제한으로 인해 발생하는 절단(Censoring) 문제를 해결하는 두 가지 구현 방법을 소개합니다. EM Unconstraining을 통한 빠른 점 추정 방식과 NumPyro를 이용한 베이즈 시계열 모델링을 통해 절단된 데이터로부터 진정한 수요를 복원하는 과정을 다룹니다.
핵심 포인트
- 절단 데이터는 상한값으로부터의 정보로서 우도에 포함 가능
- EM Unconstraining은 항공권 수익 관리에서 유래한 빠른 점 추정 방식
- NumPyro를 활용하면 트렌드, 계절성, 자기회귀를 포함한 사후 분포 추정 가능
- E-step과 M-step 반복을 통해 절단 편향을 효과적으로 제거
전 5회 시리즈 중
제 4회. 이전: 제 3회 (이론 편 · 후편) / 다음: 제 5회 (구현 편 · 신상품 + 발전 편). 전체 구성은 제 1회 서두를 참조.
1. 기존 상품의 수요 예측이 안고 있는 절단(Censoring) 문제의 특징
레이와 시대의 쌀 소동[4:1]으로 돌아가서, '기존 상품'이란 무엇인지 정리해 봅시다.
코시히카리, 아키타코마치, 히토메보레와 같은 정통 브랜드 쌀은 적어도 수년~수십 년의 판매 이력이 있습니다. - 많은 날에 캐파시티(Capacity, 재고, 발주량)가 충분히 존재하며, 수요는 캐파시티 내에서 관측됩니다. < -
일부 기간(예: 2024년 8월~10월)에만 절단이 집중된다.
이 '대부분은 정상, 일부는 절단'이라는 구조야말로 기존 상품의 특징입니다. 이 구조 덕분에:
- 정상기의 데이터는 모델의 파라미터 추정(Trend, Seasonality)에 유용함
- 절단기의 데이터는 상한(Upper bound)으로부터의 정보로서 우도(Likelihood)에 포함할 수 있음 - 두 가지를 조합함으로써 절단기의 진정한 수요를 복원할 수 있음
본 기사에서는 이 복원을 두 가지 접근 방식으로 수행합니다.
EM Unconstraining: 점 추정(Point estimation) 방식으로 계산이 빠름. Salch (1997)[1:1]가 항공권 수익 관리(Revenue Management) 분야에서 제안한 이래 실무에서 널리 사용되고 있습니다[5]. -
- NumPyro 베이즈 시계열 모델: 사후 분포(Posterior distribution)를 통해 신용 구간(Credible interval)을 얻을 수 있음. 트렌드(Trend), 계절성(Seasonality), 자기회귀(Autoregression)를 동시에 모델링할 수 있음.
2. 방법 그 1: EM 알고리즘을 통한 Unconstraining
2.1 배경: 항공권 수익 관리에서 쌀 수요 예측으로
EM Unconstraining의 원형은 1990년대 후반의 항공권 수익 관리 연구로 거슬러 올라갑니다. Salch (1997)[1:2]는 INFORMS 컨퍼런스에서 "Unconstraining Passenger Demand Using the EM Algorithm"이라는 중요한 논문을 발표하여, 만석으로 인해 절단된 항공편의 진정한 수요를 EM으로 추정하는 방법을 제시했습니다. Talluri & van Ryzin (2004)[2:1]의 교과서 The Theory and Practice of Revenue Management에서도 핵심적으로 다루어지고 있습니다. 그 이후의 주요 비교 연구로는 Queenan et al. (2007)[5:1]이 있습니다.
이 기법이 소매 수요 예측에 전용되기 시작한 것은 2000년대 후반 이후이며, 현재는 ikatsov/tensor-house 리포지토리의 demand-unconstraining.ipynb [6]를 비롯하여 여러 교육적 구현이 오픈 소스로 공개되어 있습니다.
2.2 EM 알고리즘의 직관
왜 이것으로 작동하는지 직관적으로 설명하겠습니다.
- 처음에는 절단된 날을 '그날의 수요 = 캐파시티 값'으로 취급합니다 (OLS와 동일).
- 파라미터 $\mu, \sigma$를 가추정(Pseudo-estimate)합니다. 이는 OLS의 편향된 추정치에 가깝습니다. - E-step에서 "만약 진정한 $\mu, \sigma$가 이 가추정치라면, 절단된 날의 진정한 수요는 어느 정도인가?"를 조건부 기대값으로 계산합니다. - M-step에서 그 가상 데이터를 사용하여 파라미터를 재추정합니다.
- 가파라미터가 진정한 값에 더 가까워집니다.
- 이를 반복하면 점차 절단 편향(Censoring bias)이 제거됩니다.
2.3 Python 구현
먼저 단순한 '절단이 포함된 정규 분포 모델'을 EM으로 푸는 구현을 보여드립니다.
import numpy as np
from scipy import stats
def em_unconstrain(observed, is_censored, max_iter=100, tol=1e-6):
...
2.4 제 2회의 합성 데이터로 테스트
제 2회에서 만든 쌀 소동 합성 데이터에 적용합니다.
# 제 2회의 코드로 생성된 df를 사용 (본 기사 서두에서도 로드해 주세요)
import numpy as np
import pandas as pd
...
전형적인 출력:
반복 횟수: 13
추정 μ: 109.64
추정 σ: 15.97
...
13회의 반복으로 수렴하며, 추정된 평균
다만 여기서 주의할 점이 하나 있습니다. 이 간이 EM은 "전체 기간의 절단일(censoring date)의 imputed_demand는 모두 동일한 값(조건부 평균의 해석해)이 됩니다." 일자별로 다른 값으로 복원하고 싶다면, 트렌드와 계절성을 명시적으로 포함한 다음 절의
회귀 버전 EM이 필요합니다.
2.5 트렌드·계절성이 포함된 EM
위의 구현은 "기간 전체에서
import numpy as np
from scipy.stats import norm
def em_tobit_regression(X, y, c, is_censored, max_iter=200, tol=1e-6):
...
이를 제2회차의 전체 365일 데이터에 적용하면, OLS나 Tobit MLE와 추정 결과를 비교할 수 있습니다. 전형적으로 EM의 계수는 MLE Tobit와 거의 동일한 값으로 수렴합니다(이론적으로도 EM은 Tobit의 MLE를 다른 수치 알고리즘으로 구하고 있는 것뿐이므로, 이는 예상대로입니다).
SALT2에 대하여
본 시리즈를 집필하고 있는 SALT2는 생성 AI, 예측 모델, 최적화를 결합한 맞춤형 AI 솔루션을 제공하는 AI 스타트업입니다. 수요 예측이나 재고 최적화와 같은 ML 프로젝트 외에도, AI Agent를 통한 Media 구축, 비구조화 데이터의 구조화 파이프라인 자율 개선 시스템, 컨설팅 업무 DX 등 폭넓은 영역에서 기업 과제 해결을 지원하고 있습니다. 2025년 10월에 부스트 컨설팅 주식회사(Boost Consulting Co., Ltd.)의 그룹사가 되었으며, 전략 컨설팅의 구현력과 AI·데이터 사이언스의 전문성을 결합한 지원 체계를 갖추고 있습니다. 제공 사례의 상세 내용은 SALT2의 사례 페이지에서 소개하고 있습니다.
3. 방법 그 2: NumPyro를 이용한 절단 우도(Censored Likelihood) 포함 베이즈 시계열 모델
3.1 EM의 한계
EM Unconstraining은 강력하지만 다음과 같은 제약이 있습니다.
- 분포 형태의 가정: 정규 분포를 전제로 하는 구현이 주류임 (멱 분포(Power Law)나 로그 정규 분포(Log-normal distribution)로의 확장은 가능하지만 번거로움)
- 불확실성 평가: 점 추정(Point estimation)만 가능함. 예측 구간을 자연스럽게 얻을 수 없음 (부트스트랩(Bootstrap) 등은 별도로 필요)
- 구조 모델과의 통합이 번거로움: 트렌드, 계절성, 자기회귀(Autoregression)를 동시에 다루면 E-step과 M-step 모두 복잡해짐
실무에서 "점 추정뿐만 아니라 예측의 불확실성도 알고 싶다", "트렌드나 외생 변수를 포함하고 싶다"는 경우에는 **베이즈 시계열 모델(Bayesian Time Series Model)**이 더 유연합니다. 본 절에서는 NumPyro[3:1]를 사용합니다.
3.2 모델 구조
레이와 시대의 쌀 소동 합성 데이터를 염두에 두고, 다음과 같은 구조를 구성합니다 (Juan Camilo Orduz의 블로그 "Demand Forecasting with Censored Likelihood"[8]의 접근 방식을 참고했습니다):
- 트렌드 항: 선형 (Linear)
- 계절성: 푸리에 모드 (Fourier mode, sin / cos)
- 자기회귀 항: AR(1)
- 관측 우도: 절단 정규 분포 (Censored Normal Distribution)
3.3 NumPyro를 이용한 구현
import jax
import jax.numpy as jnp
import numpyro
...
포인트는 두 가지입니다.
- 절단되지 않은 관측치의 우도만을
numpyro.handlers.mask를 사용하여numpyro.sample(..., obs=...)로 등록. - 절단된 관측치는 $\log(1 - \Phi)$를 사용하여 로그 생존 함수(log survival function)
numpyro.factor를 명시적으로 로그 우도에 더함.
이는 제3회에서 도출한 Tobit의 로그 우도를 그대로 확률 프로그램(Probabilistic Program)으로 작성한 것입니다.
3.4 MCMC 실행
import jax.numpy as jnp
import jax
from numpyro.infer import MCMC, NUTS
...
출력되는 print_summary()에서는 각 파라미터의 사후 평균(Posterior mean), 사후 분산(Posterior variance), 95% 신용 구간(Credible interval),
3.5 진정한 수요의 사후 분포 획득
베이즈 모델의 혜택은 진정한 수요에 신용 구간이 붙는다는 점입니다. 절단기의 진정한 수요에 대해 사후 예측 분포(Posterior predictive distribution)를 얻어보겠습니다.
import numpy as np
from scipy.stats import truncnorm
# 사후 샘플로부터, 절단기의 진정한 수요를 복원
...
이 그래프에서는 절단기에 주황색 신용 구간(Credible Interval)이 상단으로 넓어지며, **"이 지점의 수요는 150 ~ 250 사이의 어딘가에 있다"**라는 불확실성을 명시할 수 있어야 합니다.
보충: NumPyro vs PyMC
동일한 베이즈 모델은 PyMC로도 구현 가능합니다. PyMC에는 pm.Censored라는 편리한 분포(distribution)가 있어, rv = pm.Censored(name, dist, lower, upper)로 절단을 직접 지정할 수 있습니다[9]. 반면 NumPyro[3:2]는 명시적으로 numpyro.factor를 사용하여 로그 생존 함수(Log-survival function)를 더해주어야 합니다.
기사 수준에서는 NumPyro의 구현이 다소 무겁게 느껴질 수 있지만, JAX의 JIT 컴파일을 통한 고속성과 NUTS 샘플러의 고성능 덕분에 대규모 데이터에서는 NumPyro가 실무적으로 유리한 경우가 많습니다. 취향에 따라 선택하시기 바랍니다.
4. 「레이와 쌀 소동」기의 시뮬레이션 재현과 3가지 수법의 비교
3가지 수법(OLS / EM / 베이즈)을 실제로 합성 데이터에 적용하여 비교한 결과를 표로 정리합니다.
| 수법 | 추정된 트렌드 계수 (참값=0.0605) | RMSE (전체 기간) | RMSE (소동기만) | 95% 신용 구간 |
|---|---|---|---|---|
| OLS (절단 무시) | 0.0461 | 16.29 | 17.44 | ✗ 부정확 |
| ... |
베이즈 열의 수치는,
5. 실무상의 주의점
실제 데이터에 적용할 때는 다음의 함정에 주의하십시오.
5.1 절단 판정의 어려움
"정말로 선반이 비어 있었던 날"을 어떻게 특정할 것인가? POS 데이터만으로는 알 수 없습니다.
- 판매 수량이 캐파시티(Capacity)에 가까움 $\rightarrow$ 절단 가능성 있음
- 판매 수량이 캐파시티와 같음 $\rightarrow$ 절단 확도 높음
- 판매 수량이 캐파시티를 초과함 (추가 입고 등) $\rightarrow$ 절단이 아님
이상적으로는, **재고 데이터 (SKU 레벨의 당일 종료 시점 재고)**와 POS 데이터를 대조하여 "그날, 품절된 시각"을 특정할 수 있는 것이 최선입니다. 소매 IT 현장에서는 시각 정보가 포함된 재고 스냅샷(예: 1시간 단위 재고)이 있는지 여부에 따라 절단 보정의 정밀도가 크게 달라집니다.
5.2 임계값 (Capacity가 시간별로 변하는 경우)
캐파시티가 매일 다른 것은 일반적입니다 (입고량, 타 점포로부터의 전입 재고, 전일 잔량). 이 경우, **시변 공변량 (Time-varying covariate)**이 필요합니다. 본 기사의 샘플 코드는 이미 그렇게 되어 있으므로, capacity 배열을 데이터로부터 구축하기만 하면 됩니다.
5.3 이상치 vs. 절단
2024년 8월에는 폭염도 있었습니다. 폭염이 발생한 날 쌀 판매량이 급증한 것이 진정한 수요 증가일까요, 아니면 대체 상품(파스타, 소면, 냉동 우동)으로부터의 대체 수요 유입일까요?
이와 같이, 절단과 외생적 쇼크가 동시에 발생하는 경우, 단순한 Tobit 모델로는 양자를 분리할 수 없습니다. 외생 변수(기온, 요일, 프로모션)를 설명 변수로 추가하여, 조건부 수요 하에서의 절단 보정을 수행해야 합니다. 본 기사의 베이즈 모델은 이러한 확장이 용이합니다 (X 행렬에 기온 열을 추가하기만 하면 됩니다).
5.4 모델 선택 가이드라인
많은 실무 프로젝트에서는, 먼저 EM으로 빠르게 진단하고, 운영이 궤도에 오르면 베이즈로 이행하는 2단계 전략이 효과적입니다.
6. 차회 예고
다음 회차(제5회)에서는 더 어려운 케이스를 다룹니다.
- 신상품: 이력 자체가 없음. 유사 상품으로부터의 정보 전이를 어떻게 절단 보정과 결합할 것인가. PyTorch로 Tobit 손실 함수를 구현하여, Temporal Fusion Transformer와 같은 심층 시계열 모델에 통합하기.
- 단종 상품: 가격 변동과 재고 감소가 동시에 진행되어, 절단과 인과 추론이 얽히는 발전적 주제. 생존 분석 (
lifelines라이브러리)을 사용한 현실적인 접근법과, 현시점에서는 성숙한 해법이 존재하지 않음을 정리하기.
나아가 시리즈 전체의 총괄로서, 실무자를 위한 행동 지침 체크리스트와 참고 문헌 리스트를 제시합니다.
다음 회는 시리즈의 마지막 회입니다. 기존 상품이 '풀 수 있는 문제'였던 것과 대조적으로, 신상품과 단종 상품이라는 '아직 풀리지 않은 문제'의 최전선을 다룹니다.
SALT2에서는 함께 일할 동료를 모집하고 있습니다
SALT2에서는 본 기사에서 다룬 것과 같은 최첨단 머신러닝 (Machine Learning) 및 베이즈 통계 (Bayesian Statistics) 기법을 실제 프로젝트에 적용하고, 비즈니스 성과까지 책임지고 전달하고자 하는 엔지니어/데이터 사이언티스트를 지속적으로 모집하고 있습니다. 최신 AI·LLM 논문 독해 모임이나 현장에서 얻은 개발 노하우를 공유하는 일이 일상적으로 이루어지는 환경입니다. 관심이 있으신 분은 SALT2 공식 사이트에서 지원 및 문의해 주시기 바랍니다.
Salch, J. (1997). "Unconstraining Passenger Demand Using the EM Algorithm," Proceedings of the INFORMS Conference, Dallas, TX. 1차 자료는 온라인에 공개되지 않았으며, Talluri & van Ryzin (2004) 등의 2차 문헌을 통해 인용되었습니다. 구현 예시로는 ikatsov/tensor-house를 참조하십시오. ↩︎ ↩︎ ↩︎ -
Talluri, K. T. & van Ryzin, G. J. (2004). The Theory and Practice of Revenue Management. Springer. https://doi.org/10.1007/b139000 ↩︎ ↩︎ -
NumPyro 공식 문서. https://num.pyro.ai/ ↩︎ ↩︎ ↩︎
레이와 시대의 쌀 소동 — Wikipedia. https://ja.wikipedia.org/wiki/令和の米騒動 ↩︎ ↩︎
Queenan, C. C., Ferguson, M., Higbie, J., & Kapoor, R. (2007). "A Comparison of Unconstraining Methods to Improve Revenue Management Systems," Production and Operations Management, 16(6), 729–746. https://doi.org/10.1111/j.1937-5956.2007.tb00292.x ↩︎ ↩︎ -
Katsov, I. ikatsov/tensor-house GitHub 리포지토리. demand-forecasting/demand-unconstraining.ipynb에 EM Unconstraining의 구현 예시가 공개되어 있습니다. https://github.com/ikatsov/tensor-house ↩︎ ↩︎ -
AysajanE, pricing-revenue-analytics-course-codes GitHub 리포지토리. EM 알고리즘을 이용한 unconstraining 교육용 노트북을 포함하고 있습니다. https://github.com/AysajanE/pricing-revenue-analytics-course-codes ↩︎ -
Orduz, J. C. "Demand Forecasting with Censored Likelihood." https://juanitorduz.github.io/demand/ ↩︎ ↩︎
PyMC 공식 문서 pm.Censored. 절단 가능도 (Censored Likelihood)를 직접 기술할 수 있습니다. https://www.pymc.io/projects/docs/en/stable/api/distributions/generated/pymc.Censored.html ↩︎ -
주식회사 인테이지 「데이터로 보는 레이와 시대의 쌀 소동 2025년의 동향과 비축미의 효과란」 (Shiru Gallery by INTAGE). https://gallery.intage.co.jp/komesoudou_2/ ↩︎ -
미쓰비시 종합연구소 「'레이와 시대의 쌀 소동' (3) 쌀 가격 급등의 구조와 비축미 방출의 의미」. https://www.mri.co.jp/knowledge/column/20250311_2.html ↩︎
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn ML의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기