TL;DR
- AI Sales Forecasting 프로젝트는 모델보다 데이터 설계(스키마/시간 의미/누수 방지/품질 규칙)에서 승부가 납니다.
- 판매 예측 데이터는 최소한 sales(타깃) + calendar(캘린더/이벤트) + price + promo + inventory/stockout 축으로 나눠 설계하는 게 안전합니다.
- 시계열 피처 조인은 포인트-인-타임(과거 시점 기준) 정합성을 보장해야 누수(leakage)를 막을 수 있습니다.
- 품절(stockout)은 관측 판매를 검열(censored)로 만들고 예측 편향을 유발할 수 있으니, 최소한 stockout_flag는 데이터 계약에 포함하세요.
- 품질 관리는 "문서"가 아니라 검증 가능한 규칙(Expectation Suite)로 자동화하는 게 실무적으로 맞습니다.
본문
TOC
- 데이터 모델링 목표와 원칙(데이터 계약)
- “정답 테이블(Training/Inference View)” 스키마
- 원천 테이블 설계(판매/가격/프로모션/재고/캘린더)
- 시간 의미(이벤트 시간 vs 기준 시점)와 누수 방지
- 결측·이상치·품절(검열 수요) 처리
- 품질 검증 규칙(자동화 템플릿)
- 트러블슈팅 3개
- 실무 체크리스트: 배포 전 / 운영 중
- FAQ
- 다음 글 예고(Part 3)
1) 데이터 모델링 목표와 원칙(데이터 계약)
AI Sales Forecasting에서 데이터 모델링의 목표는 “많이 모으기”가 아니라, 학습/추론에서 동일한 의미로 재현되는 데이터를 만드는 것입니다.
이번 회차는 그 목적을 위해 데이터 계약(Data Contract)을 다음 4가지를 중심으로 고정합니다.
- 타깃(y)의 의미를 고정: 판매량(수량)인지, 매출인지, 순매출(반품 차감)인지
- 시간 기준을 고정: 일/주 단위, 타임존, 집계 컷오프(예: D+1 새벽 확정)
- 피처의 "미래 가용성"을 고정: 예측 시점에 알 수 있는 값만 사용(누수 방지)
- 검열(품절)·결측을 구분: "0 판매"와 "판매 불가(품절/미운영)"를 섞지 않기
Why it matters: 모델은 바꿔도 되지만, 데이터 의미가 흔들리면 재현·운영이 무너집니다.
특히 누수는 오프라인 점수를 망치지 않고 "운영에서만" 터지기 때문에 더 위험합니다.
2) “정답 테이블(Training/Inference View)” 스키마
현업에서 가장 많이 쓰이는 형태는 롱 포맷 + 시리즈 키 + 날짜(ds) 입니다. (M5 리테일 데이터도 판매/캘린더/가격을 분리해 제공하는 구조로 유명합니다.)
2-1. 최소 스키마(권장)
| 컬럼 | 예 | 비고 |
|---|---|---|
| ds | 2026-02-08 | 기준 날짜(일/주) |
| series_id | SKU123_STORE01 | SKU×매장 등 |
| y | 17 | 타깃(판매) |
| is_open | 1/0 | 영업일 여부 |
| is_listed | 1/0 | 취급 여부(입점/단종) |
| stockout_flag | 1/0 | 품절(검열) 여부 |
| price | 10,900 | 실판매가/기준가 |
| promo_flag | 1/0 | 프로모션 여부 |
| event_name | 설날/블프 | 캘린더 이벤트 |
핵심 규칙:
y=0은 “팔 수 있었는데 안 팔림”을 의미해야 합니다.is_open=0또는is_listed=0이면 그날은 0이 아니라 결측 취급이 더 안전합니다(훈련셋 생성 단계에서 제외/마스킹).stockout_flag=1이면y는 관측 판매일 뿐, "진짜 수요"가 아닐 수 있습니다(검열).
Why it matters: 이 뷰가 고정되면, 모델/플랫폼(Azure AutoML, Vertex, 오픈소스)이 바뀌어도 파이프라인은 유지됩니다.
3) 원천 테이블 설계(판매/가격/프로모션/재고/캘린더)
여기서는 "정답 뷰"를 만들기 위한 원천 테이블 묶음을 제안합니다. (정확히 M5가 sales + calendar + sell_prices 형태로 분리해 배포한 구조가 참고가 됩니다.)
3-1. 권장 테이블 맵
| 구분 | 테이블 | 키(예) | 설명 |
|---|---|---|---|
| 타깃 | fact_sales |
ds, sku_id, store_id | 판매(수요의 관측치) |
| 캘린더 | dim_calendar |
ds | 요일/월/공휴일/이벤트 |
| 가격 | fact_price |
sku_id, store_id, effective_from~to | 가격(유효기간형) |
| 프로모션 | fact_promo_plan |
sku_id, store_id, start~end | 계획/집행 프로모션 |
| 재고/품절 | fact_inventory_snapshot |
as_of_ts, sku_id, store_id | 재고 스냅샷 |
| 마스터(정적) | dim_product, dim_store |
sku_id / store_id | 카테고리/지역 등 |
Why it matters: 판매 예측에서 "설명 변수"는 대부분 캘린더/가격/프로모션/재고에서 나오고, 이 축이 분리돼야 시간 의미를 제대로 관리할 수 있습니다.
4) 시간 의미(이벤트 시간 vs 기준 시점)와 누수 방지
4-1. 필수 시간 컬럼 2개: event_time과 as_of_time
event_time: “그 일이 실제로 발생한 시간”(판매 발생 시점, 가격 적용 시작 시점)as_of_time: “우리 시스템이 그 값을 언제 알았는지(수집/확정 시점)”
시계열 학습에서 가장 흔한 사고는 event_time만 보고 조인해서, 실제로는 나중에 확정된 값을 과거에 섞어 넣는 것입니다. 그래서 피처 조인은 포인트-인-타임 정합성(label 시점에 존재하던 피처 값만 조인)을 강제하는 방식이 권장됩니다.
4-2. “피처 가용성 분류”를 컬럼 메타로 관리
| 분류 | 예 | 학습/추론 |
|---|---|---|
| Static | 상품 카테고리, 매장 지역 | 항상 가능 |
| Past-only | 지난 7일 판매 합, lag 피처 | 학습 가능 / 추론은 cutoff 이전까지만 |
| Future-known | 캘린더, 계획된 프로모션 | 학습/추론 모두 가능 |
| Future-unknown | 실시간 재고, 실시간 경쟁사 가격 | 추론 시점에 없으면 누수 |
Azure AutoML도 시계열에서 lag/rolling 피처를 만들고 활용하는 개념을 문서로 설명합니다(결국 "과거로부터 만든 피처"입니다).
Why it matters: 누수는 모델이 아니라 "조인"에서 생깁니다. 포인트-인-타임 조인을 강제하면 이 계열의 사고를 크게 줄일 수 있습니다.
5) 결측·이상치·품절(검열 수요) 처리
5-1. 품절(stockout)은 반드시 라벨링
품절이 있으면 관측 판매는 "진짜 수요"보다 작을 수 있고, 이 편향이 누적되면 시스템적으로 과소 예측을 만들 수 있습니다. 신선 리테일에서 검열 수요(censored demand) 문제를 정면으로 다룬 데이터셋/연구도 나와 있습니다.
최소 실무 대응(필수):
stockout_flag생성(재고=0 + 판매 제한 신호)stockout_flag=1구간을 학습에서 제외하거나, 별도 “수요 복원(imputation)” 단계를 둡니다(Part 8에서 런북으로 다룹니다).
5-2. “0 판매”와 “관측 불가”를 분리
- 휴점/미취급/시스템 장애는
y=0으로 넣지 말고is_open,is_listed,data_missing_flag로 분리하세요. - 리테일 공개 데이터도 판매 외에 캘린더/가격/이벤트 같은 컨텍스트를 함께 제공하는 이유가 여기 있습니다.
Why it matters: 품절과 결측을 섞으면, 모델은 "수요가 없는 상품"으로 학습합니다. 그 다음부터는 모델을 바꿔도 답이 안 나옵니다.
6) 품질 검증 규칙(자동화 템플릿)
품질 규칙은 문서가 아니라 검증 가능한 형태로 남겨야 합니다. Great Expectations는 이런 "검증 가능한 주장(Expectation Suite)"을 모아 관리하고, 결과를 문서(Data Docs)로 만들 수 있다고 설명합니다.
6-1. 핵심 규칙(바로 복사해서 쓰는 체크)
(A) 키/중복
(ds, series_id)는 유일해야 함- 날짜는 연속(캘린더 기준)이어야 함
(B) 값 범위
y >= 0price > 0(0 또는 음수는 오류)promo_start <= promo_end
(C) 의미 규칙
is_open=0이면y는 NULL(또는 학습 제외)is_listed=0이면y는 NULL(또는 학습 제외)stockout_flag=1이면 "검열 구간"으로 태깅되어야 함
6-2. 예시: DDL(스켈레톤)
-- 판매(타깃)
create table fact_sales (
ds date not null,
sku_id string not null,
store_id string not null,
units_sold double, -- 원천이 정수여도 환산/반품 처리로 double 가능
event_time timestamp, -- 실제 판매 발생 시간(있으면)
as_of_time timestamp not null, -- 확정/적재 시점
primary key (ds, sku_id, store_id)
);
-- 캘린더(미래에도 알 수 있는 값)
create table dim_calendar (
ds date primary key,
dow int,
week_of_year int,
is_holiday int,
event_name string
);
-- 가격(유효기간형)
create table fact_price (
sku_id string,
store_id string,
effective_from date,
effective_to date,
price double,
as_of_time timestamp not null
);
-- 프로모션(계획/집행)
create table fact_promo_plan (
sku_id string,
store_id string,
promo_id string,
start_date date,
end_date date,
promo_type string,
discount_rate double,
as_of_time timestamp not null
);
-- 재고 스냅샷(품절 파생)
create table fact_inventory_snapshot (
as_of_ts timestamp,
sku_id string,
store_id string,
on_hand double,
on_order double
);
Why it matters: 품질 규칙이 자동화되면, 데이터가 깨질 때 "모델 성능"이 아니라 "입력 데이터"에서 바로 원인을 찾을 수 있습니다.
7) 트러블슈팅(증상→원인→해결) 3개
- 증상: 오프라인 점수는 좋은데 운영에서만 성능 붕괴
- 원인 후보: 포인트-인-타임 정합성 없는 조인(누수)
- 해결: label 시점 기준으로 피처를 조인하는 규칙(시간 조건)을 강제
증상: 특정 상품군만 지속 과소 예측
- 원인 후보: 품절 구간이
y=0처럼 학습됨(검열 수요) - 해결:
stockout_flag생성 후 제외/복원 파이프라인 도입
- 원인 후보: 품절 구간이
증상: 프로모션 기간만 예측이 심하게 빗나감
- 원인 후보: 계획 프로모션 테이블과 실제 집행 프로모션이 섞임(시간/정의 불일치)
- 해결:
fact_promo_plan(계획)과fact_promo_actual(집행)을 분리하고, 추론에서는 “계획”만 사용
Why it matters: 장애의 80%는 모델이 아니라 데이터 정의/조인/품절 처리에서 나옵니다.
8) 실무 체크리스트 2종
배포 전(데이터) 체크리스트
-
y정의(순판매/총판매/매출)가 문서+스키마로 고정 -
(ds, series_id)유일성 보장 - 포인트-인-타임 조인 규칙이 테스트로 검증됨
-
stockout_flag,is_open,is_listed가 존재 - Expectation Suite로 품질 규칙이 자동화됨
운영 중(데이터) 체크리스트
- 캘린더 갱신 누락(미래 날짜 없음) 알람
- 가격 유효기간 겹침/공백 탐지
- 프로모션 기간 이상(역전/중복) 탐지
- 품절 비율 급증(재고 파이프라인 장애) 알람
Why it matters: 예측 시스템은 “데이터 제품”입니다. 데이터 운영이 무너지면, 어떤 모델도 복구책이 아닙니다.
9) FAQ
Q. 판매 데이터만으로는 안 되나요?
A. 할 수는 있지만, 실무 리테일에서는 캘린더/가격/프로모션이 성능과 해석에 크게 영향을 줍니다. 공개 리테일 벤치마크도 이 컨텍스트(캘린더/가격)를 함께 제공합니다.Q. 재고 데이터가 없으면 품절 처리를 못 하나요?
A. 못 하는 건 아니지만, 품절은 관측 판매를 검열로 만들어 편향을 유발할 수 있으니, 최소한 "판매 제한 신호"를 별도로 기록하는 쪽이 안전합니다.Q. 누수 방지는 결국 뭐 하나만 지키면 되나요?
A. 핵심은 "label 시점에 존재하던 피처만 조인"입니다. 이걸 포인트-인-타임 정합성으로 강제하면 대부분 정리됩니다.Q. lag/rolling 피처는 언제 만들면 되나요?
A. 원천 테이블에서 미리 만들기보다, 학습셋 빌드 단계에서 컷오프 기준으로 생성하는 편이 안전합니다(누수 방지). Azure 문서도 lag/rolling 피처 개념을 별도로 설명합니다.Q. Great Expectations 같은 도구는 왜 쓰나요?
A. 품질 규칙을 "검증 가능한 형태(Expectation Suite)"로 남기고 결과를 문서(Data Docs)로 만들 수 있기 때문입니다.
10) 다음 글 예고(Part 3)
Part 3에서는 베이스라인 2개 + rolling-origin 백테스트 + 리포트 템플릿을 코드 중심으로 정리합니다. (rolling forecasting origin/시계열 CV 개념은 FPP에서도 표준으로 다룹니다.)
결론 (요약 정리)
- 판매 예측 데이터 모델링은 스키마(축 분리) + 시간 의미(as_of) + 포인트-인-타임 조인이 핵심입니다.
- 품절은 "0 판매"가 아니라 검열 수요일 수 있으니, 최소한
stockout_flag를 계약에 넣어야 합니다. - 품질 관리는 문서가 아니라 자동 검증 규칙으로 운영해야 합니다.
References
- (M5 Forecasting - Accuracy (Data), Accessed 2026-02-08)[https://www.kaggle.com/c/m5-forecasting-accuracy/data]
- (M5 dataset overview (prices, promotions, holidays), Accessed 2026-02-08)[https://colab.research.google.com/github/ikyath/M5-Forecasting-Accuracy-Kaggle/blob/master/M5_Forecast_Encoder_Decoder_Final.ipynb/]
- (Point-in-time feature joins (prevent data leakage), Accessed 2026-02-08)[https://docs.databricks.com/aws/en/machine-learning/feature-store/time-series]
- (Point-in-time feature joins - Azure Databricks, Accessed 2026-02-08)[https://learn.microsoft.com/en-us/azure/databricks/machine-learning/feature-store/time-series]
- (FreshRetailNet-50K: Stockout-annotated censored demand dataset, 2025-05-22)[https://arxiv.org/abs/2505.16319]
- (Censored Demand Estimation in Retail, Accessed 2026-02-08)[https://dl.acm.org/doi/10.1145/3154489]
- (Expectation Suite, Accessed 2026-02-08)[https://docs.greatexpectations.io/docs/0.18/reference/learn/terms/expectation_suite/]
- (Data Docs, Accessed 2026-02-08)[https://docs.greatexpectations.io/docs/0.18/reference/learn/terms/data_docs]
- (Lag features for time-series forecasting in AutoML, Accessed 2026-02-08)[https://learn.microsoft.com/en-us/azure/machine-learning/concept-automl-forecasting-lags?view=azureml-api-2]
- (Time series cross-validation (rolling forecasting origin), Accessed 2026-02-08)[https://otexts.com/fpp3/tscv.html]
'AI > Technical' 카테고리의 다른 글
| AI Sales Forecasting 4: 피처 기반 ML로 판매 예측 설계 (1) | 2026.02.09 |
|---|---|
| AI Sales Forecasting 백테스트 설계: Rolling CV·베이스라인·리포트 (3) (0) | 2026.02.09 |
| AI Sales Forecasting: AI 기반 판매 예측 설계 로드맵 (1) (0) | 2026.02.08 |
| vibe coding과 ADHD: 생산성 올리고 사고 줄이는 운영법 (2) | 2026.02.04 |
| vibe coding과 ADHD: 잘 맞는 지점과 위험 구간 (2) | 2026.02.04 |