Appearance
📝 Walmart dự báo sai 2% = mất $100M tồn kho — Forecasting: Đừng dùng crystal ball, dùng data
Mở đầu — "Nhập thêm 40% hàng Tết đi, bán chắc hết!"
Quân, 30 tuổi, Supply Chain Data Analyst tại FreshMart — chuỗi siêu thị 45 cửa hàng tại miền Nam Việt Nam. Revenue ~2,800 tỷ VND/năm. Team Supply Chain 12 người: 3 DA (Quân là lead), 4 planner, 5 logistics. Hệ thống SAP ERP, data warehouse trên BigQuery, dashboard trên Looker.
Quân join FreshMart 2.5 năm. Background: cử nhân Logistics & Supply Chain Management tại ĐH Bách Khoa TP.HCM, 3 năm kinh nghiệm trước đó tại công ty FMCG. Quân giỏi SQL, Python cơ bản, Pandas tốt — nhưng chưa bao giờ build forecast model nghiêm túc. Từ trước đến nay, demand planning ở FreshMart dựa vào kinh nghiệm + Excel — anh Hùng, Supply Chain Director 45 tuổi, 18 năm ngành retail, tự tin: "Tao forecast bằng ruột, chưa bao giờ sai quá."
Cuối tháng 10/2025, anh Hùng triệu tập họp planning cho Tết Nguyên Đán 2026:
"Năm ngoái Tết bán tốt. Năm nay kinh tế khá hơn, nhập thêm 40% hàng so với năm ngoái. Bánh kẹo, bia, nước ngọt — full container. Quân ơi, pull data năm ngoái ra, cộng 40% là xong."
Quân ngần ngại: "Anh ơi, 40% dựa trên cơ sở nào?"
"Kinh nghiệm! 18 năm ngành retail, tao biết Tết năm nào cũng tăng. Năm ngoái tăng 35%, năm nay kinh tế tốt hơn thì 40% là hợp lý."
Quân cảm thấy có gì đó sai — nhưng chưa có tool để phản bác. Anh nhớ lại khóa Data Analytics đã học về decomposition, trend, seasonality... nhưng chưa bao giờ thử áp dụng cho demand planning.
Phần 1: Tết 2026 — Thảm họa tồn kho
"Sao hàng còn đầy kho mà Tết đã qua rồi?"
Tết Nguyên Đán 2026 kết thúc. Kết quả:
| Category | Nhập (dựa +40%) | Bán thực tế | Tồn kho | Thiệt hại |
|---|---|---|---|---|
| Bánh kẹo | 180,000 hộp | 125,000 hộp | 55,000 hộp (30%) | Hàng hết hạn → hủy 60% |
| Bia | 240,000 thùng | 210,000 thùng | 30,000 thùng (12%) | Tồn kho 3 tháng |
| Nước ngọt | 300,000 thùng | 195,000 thùng | 105,000 thùng (35%) | Over-stock → chiếm kho 2 tháng |
| Mứt Tết | 50,000 hộp | 22,000 hộp | 28,000 hộp (56%) | Sản phẩm seasonal → hủy 90% |
| Thịt nguội | 80,000 kg | 72,000 kg | 8,000 kg (10%) | Hàng đông lạnh → chi phí kho |
Tổng thiệt hại ước tính: ~18 tỷ VND — bao gồm hàng hủy (12 tỷ), chi phí kho thừa (3 tỷ), opportunity cost vốn bị đọng (3 tỷ).
CEO gọi họp khẩn: "18 tỷ là 0.6% revenue cả năm. Bộ phận Supply Chain giải thích đi."
Anh Hùng im lặng. Quân biết: đây là lúc data phải lên tiếng.
Root Cause Analysis — Tại sao forecast sai?
Quân pull data 5 năm ra phân tích:
python
import pandas as pd
import numpy as np
# Data 5 năm — tăng trưởng Tết so với baseline
tet_growth = {
2022: {'actual_growth': 0.42, 'economy': 'recovery_post_covid'},
2023: {'actual_growth': 0.38, 'economy': 'moderate'},
2024: {'actual_growth': 0.28, 'economy': 'slowdown'},
2025: {'actual_growth': 0.31, 'economy': 'stable'},
2026: {'actual_growth': 0.18, 'economy': 'consumers_cautious'} # Actual
}
# Anh Hùng: "Năm ngoái 35%, năm nay 40%"
# Actual: 18% → sai 22 percentage points!Quân phát hiện 3 sai lầm trong cách forecast của anh Hùng:
Sai lầm 1: Nhìn 1 năm, không nhìn trend dài hạn
"Năm ngoái tăng 35%" — nhưng nhìn 5 năm, trend thực tế là Tết growth đang giảm dần: 42% → 38% → 28% → 31% → 18%. Consumers đang thay đổi hành vi — mua online nhiều hơn, đi du lịch Tết thay vì ở nhà ăn uống, giới trẻ ít mua bánh kẹo truyền thống.
Sai lầm 2: "Kinh tế tốt hơn → mua nhiều hơn" là oversimplification
GDP tăng ≠ tiêu dùng Tết tăng. Consumers phân bổ chi tiêu Tết sang du lịch, giải trí, quà tặng trải nghiệm — basket bánh kẹo/bia giảm dần. Structural change không thể capture bằng "cộng thêm %".
Sai lầm 3: Không phân biệt Seasonality vs One-time Spike
Tết 2022 tăng 42% vì pent-up demand sau COVID — đó là one-time effect, không phải seasonal norm. Dùng 2022 làm reference point = overestimate.
Phần 2: Quân bắt đầu học Forecasting
"Nếu anh Hùng forecast bằng ruột, tôi sẽ forecast bằng data"
Sau cuộc họp CEO, anh Hùng giao Quân nhiệm vụ: "Xây forecast model cho Mid-Autumn Festival tháng 9 tới. Lần này phải có số liệu cụ thể, không được đoán."
Quân mở sách Forecasting: Principles and Practice của Rob Hyndman — cuốn bible về forecasting mà giảng viên data analytics từng recommend. Quân bắt đầu học từ zero.
Step 1: Decompose historical data
python
from statsmodels.tsa.seasonal import seasonal_decompose
import matplotlib.pyplot as plt
# Monthly revenue FreshMart — 4 năm (2022-2025)
# Revenue triệu VND per month
dates = pd.date_range('2022-01-01', periods=48, freq='MS')
# Simulate revenue với trend tăng + Tết seasonality
np.random.seed(30)
base = 180_000 # 180 tỷ/tháng baseline
trend = np.linspace(0, 60_000, 48) # Trend tăng ~60 tỷ over 4 years
seasonal_pattern = [1.0, 1.45, 0.85, 0.90, 0.95, 1.0,
0.95, 1.05, 1.15, 1.0, 1.05, 1.20] # Tết = tháng 2
seasonal = np.tile(seasonal_pattern, 4)
noise = np.random.normal(0, 8000, 48)
revenue = (base + trend) * seasonal + noise
ts = pd.Series(revenue, index=dates, name='Revenue (triệu VND)')
# Decompose
result = seasonal_decompose(ts, model='multiplicative', period=12)Kết quả decomposition cho Quân thấy rõ:
- Trend: Revenue tăng đều ~15%/năm
- Seasonality: Tháng 2 (Tết) spike 45%, tháng 9 (Mid-Autumn) spike 15%, tháng 3-4 thấp nhất
- Residual: Noise nhỏ — model capture tốt
"Hóa ra Tết spike không phải random — nó có PATTERN rõ ràng. Và pattern đó đang thay đổi theo thời gian," Quân ghi nhận.
Step 2: Học và áp dụng forecasting methods
Quân thử 4 methods cho Mid-Autumn 2026:
| Method | MAPE trên test set | Nhận xét |
|---|---|---|
| Naïve | 22.4% | Quá đơn giản, không capture seasonality |
| SMA(12) | 18.1% | Smooth quá, miss seasonal peak |
| SES (α=0.3) | 19.7% | Flat forecast — không capture trend/season |
| Holt-Winters | 6.8% | Capture cả trend + seasonality → best! |
"Holt-Winters với 3 parameters (α, β, γ) mà MAPE chỉ 6.8%! Trong khi anh Hùng forecast bằng kinh nghiệm sai 22 percentage points cho Tết," Quân hào hứng.
Step 3: Prediction intervals — Không chỉ 1 con số
Phát hiện quan trọng nhất của Quân:
"Forecast không phải 1 con số — nó là 1 RANGE. Anh Hùng nói 'nhập 180,000 hộp bánh kẹo' — nhưng đúng ra phải nói 'forecast 125,000 ± 20,000 hộp (95% CI: 85,000 — 165,000)'. Nếu nhập theo upper bound = 165,000 thì worst case tồn kho ít hơn nhiều."
python
# Forecast với prediction interval
from statsmodels.tsa.holtwinters import ExponentialSmoothing
model = ExponentialSmoothing(ts, trend='add', seasonal='mul',
seasonal_periods=12).fit()
forecast = model.get_forecast(steps=6)
ci = forecast.conf_int(alpha=0.05)
# Point forecast + interval
print("Mid-Autumn Demand Forecast (Bánh kẹo):")
print(f" Point forecast: 125,000 hộp")
print(f" 95% PI: [{int(ci.iloc[0, 0]):,} — {int(ci.iloc[0, 1]):,}]")
print(f" ↳ Nhập theo upper bound: tránh stockout")
print(f" ↳ Nhập theo point: balance risk")
print(f" ↳ Nhập theo lower bound: conservative, risk stockout")Phần 3: Mid-Autumn Festival — Redemption
Forecast model deployment
Quân present cho anh Hùng và team:
"Em forecast demand cho Mid-Autumn Festival tháng 9/2026 bằng Holt-Winters model. Model đã test trên historical data với MAPE 6.8% — nghĩa là trung bình forecast sai khoảng 7%, so với cách cũ sai 20-30%."
| Category | Old method (anh Hùng) | Quân's forecast | 95% PI |
|---|---|---|---|
| Bánh Trung Thu | 120,000 hộp (+30%) | 95,000 hộp | 82,000 — 108,000 |
| Bia | 85,000 thùng | 78,000 thùng | 70,000 — 86,000 |
| Nước ngọt | 110,000 thùng | 88,000 thùng | 76,000 — 100,000 |
| Trà | 45,000 thùng | 42,000 thùng | 36,000 — 48,000 |
Anh Hùng ban đầu skeptical: "Máy tính thì biết gì về thị trường?"
Quân giải thích: "Model không biết 'thị trường' — nhưng nó biết PATTERN. Trend đang giảm nhẹ cho Trung Thu do giới trẻ ít ăn bánh truyền thống hơn. Seasonal spike vẫn có nhưng amplitude giảm dần. Model capture được cái mà kinh nghiệm không notice: sự THAY ĐỔI DẦN DẦN."
Kết quả Mid-Autumn 2026
| Category | Forecast (Quân) | Actual | Error | Old method Error |
|---|---|---|---|---|
| Bánh Trung Thu | 95,000 | 91,000 | 4.4% | ~31% (nếu theo anh Hùng) |
| Bia | 78,000 | 80,500 | 3.2% | ~5.6% |
| Nước ngọt | 88,000 | 84,000 | 4.8% | ~31% |
| Trà | 42,000 | 43,500 | 3.6% | ~3.4% |
Overall MAPE: 4.0% — excellent accuracy!
Tồn kho dư: chỉ ~5% overall (so với 30% Tết 2026). Tiết kiệm ước tính: ~8 tỷ VND thiệt hại tránh được.
CEO biểu dương team Supply Chain, đặc biệt khen model forecasting. Anh Hùng — lần đầu tiên trong 18 năm — thừa nhận: "Data forecast tốt hơn ruột, tao phải học thêm."
Phần 4: Bài học lớn — Khi Forecast Fail
COVID đã phá hủy mọi forecast như thế nào
Quân nhớ lại 2020 — năm FreshMart gần phá sản vì forecast sai hoàn toàn:
"Tháng 1/2020, mọi model forecast revenue Q2 tăng 12% theo trend. Tháng 3 — COVID lockdown. Revenue giảm 65%. Không model nào predict được Black Swan."
Bài học Quân chia sẻ trong buổi họp team:
Forecast ≠ Prediction — Forecast là "best guess GIVEN no structural change". Nếu thế giới thay đổi fundamentally, forecast cũ vô nghĩa.
Always use prediction intervals. Point forecast = dangerous precision. Interval = honest uncertainty. Khi CEO hỏi "Revenue Q3 bao nhiêu?", đừng nói 500 tỷ — nói 450-550 tỷ (95% CI).
Re-forecast regularly. Model train trên data cũ sẽ decay. Quân set up monthly re-training pipeline: mỗi tháng có actual data mới → retrain model → update forecast.
Combine model + domain expertise. Quân không bỏ hoàn toàn kinh nghiệm anh Hùng — anh ấy biết thị trường local, biết competitor đang làm gì, biết customer sentiment. Model cho baseline, expert cho adjustment — Holt-Winters forecast ± expert judgment = best.
Monitor forecast accuracy continuously. Quân build Looker dashboard track MAPE hàng tháng. Nếu MAPE > 15% liên tục 3 tháng → retrain model hoặc investigate structural change.
Thế Giới Di Động — Bài học forecast khuyến mãi
Quân đọc case study về Thế Giới Di Động — chuỗi bán lẻ điện tử lớn nhất Việt Nam:
"TGDĐ từng dự báo demand cho iPhone mới bằng 'cảm giác' — năm 2023 nhập 500,000 máy cho pre-order campaign, thực tế chỉ bán 340,000 trong tháng đầu. 160,000 máy tồn kho → vốn bị đọng ~1,600 tỷ VND trong 2 tháng."
Sau đó, TGDĐ build demand forecasting system dùng Holt-Winters cho baseline demand + regression adjustment cho promotion effect. Kết quả: forecast accuracy cải thiện từ 68% lên 89% — tiết kiệm ~500 tỷ VND tồn kho/năm.
Kết — "Forecasting không phải tiên tri"
6 tháng sau, Quân đã build forecasting pipeline hoàn chỉnh cho FreshMart:
📋 FRESHMART FORECASTING SYSTEM (by Quân)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Data: 4 năm monthly data, 45 stores, 2000+ SKUs
Model: Holt-Winters (top categories), SMA (long-tail)
Accuracy: Overall MAPE 5.2% (vs 22% old method)
Pipeline: Monthly retrain → BigQuery → Looker dashboard
Savings: ~25 tỷ VND/year inventory cost reduction
Process:
1. Pull actual data monthly (automated from SAP)
2. Retrain Holt-Winters per category
3. Generate forecast + 95% PI
4. Review with Supply Chain team (expert adjustment ±5%)
5. Finalize order quantities
6. Track forecast vs actual → feedback loopAnh Hùng giờ nhìn Quân mỗi sáng và nói: "Mày biết không, 18 năm tao forecast bằng ruột. Giờ tao biết — ruột tao có MAPE 22%. Thấp hơn cả SMA."
Quân cười: "Forecasting không phải tiên tri, anh. Nó chỉ là cách dùng quá khứ để GIẢM bất định về tương lai. Không perfect — nhưng tốt hơn đoán rất nhiều."
💡 Key Takeaways từ câu chuyện Quân
- Kinh nghiệm ≠ Accuracy — 18 năm kinh nghiệm nhưng MAPE 22%. Holt-Winters chạy trong 5 phút đạt MAPE 5%.
- Forecast sai 2% = mất tỷ VND — Walmart từng mất $100M vì forecast error 2% trên 11,000 stores.
- Prediction interval > Point forecast — Đừng nói "nhập 100K hộp". Nói "85K-115K, recommend 100K".
- Model + Expert = Best — Data cho baseline, expert cho context. Không thay thế nhau — bổ sung.
- COVID lesson — No model predicts Black Swans. Always have contingency plan.