Đến nội dung chính
ERP Thực Chiến
Thư viện
Menu

WAPE là gì: đo độ chính xác dự báo bán hàng trước khi đặt hàng

WAPE là gì, đọc cùng Bias thế nào, vì sao món bán chậm luôn có WAPE cao, và số dự báo đi vào đề xuất bổ sung hàng trên BC, LS Central ra sao.

WAPE (Weighted Absolute Percentage Error) là tổng sai lệch tuyệt đối giữa dự báo và số bán thật của từng ngày, chia cho tổng số bán thật. WAPE 40% nghĩa là cứ bán 100 cái thì dự báo trượt tổng cộng 40 cái, trượt lên hay xuống đều tính. Đọc WAPE luôn phải kèm Bias, con số cho biết dự báo nghiêng về dư hay thiếu.

Mọi con số trong bài tính trên dữ liệu mô phỏng 6 tháng của một chuỗi cửa hàng bánh và kem dựng để demo, không phải dữ liệu thật của khách hàng nào: 74 cặp mặt hàng và cửa hàng, kỳ kiểm tra 28 ngày từ 22/08 đến 18/09/2026. Phép đo chạy bằng AL trong Business Central có LS Central, một bản Python viết riêng ra cùng kết quả.

Công thức WAPE và Bias#

text
WAPE = Tổng |bán thật - dự báo| của từng ngày / Tổng bán thật × 100
Bias = (Tổng dự báo - Tổng bán thật) / Tổng bán thật × 100

WAPE lấy sai số từng ngày rồi mới cộng, nên ngày dư và ngày thiếu không bù cho nhau. Bias cộng tổng trước rồi mới trừ, nên dư và thiếu bù nhau. Bias dương là dự báo cao hơn thực tế, đặt hàng theo đó dễ tồn thừa. Bias âm thì dễ hết hàng.

Ví dụ một mặt hàng trong 28 ngày bán 226 cái. Cộng sai lệch từng ngày được 55 cái, WAPE = 55 / 226 = 24%. Tổng dự báo 250 cái, Bias = (250 - 226) / 226 = +11%.

Chỉ số hay gặp khác là MAPE, chia sai số của từng kỳ cho số bán của chính kỳ đó. Đo theo ngày, ngày bán 0 làm phép chia không tính được, mà món bán chậm có rất nhiều ngày như vậy. WAPE chia một lần cho tổng nên không vướng.

Vì sao món bán chậm có WAPE rất cao dù tổng gần khớp#

Ba dòng trong bảng độ chính xác, cùng một điểm bán dạng nhà hàng:

MónBán thậtDự báoWAPEBias
A7710976,5%+41,6%
B587562,7%+29,3%
C252891,7%+12%

Món C có tổng gần khớp nhất mà WAPE cao nhất. Món này bán khoảng 0,9 cái mỗi ngày. Dự báo đều 1 cái/ngày, còn thực tế hôm 0, hôm 3, hôm 0, hôm 2. Bốn ngày minh họa:

NgàyBán thậtDự báoSai lệch tuyệt đối
1011
2312
3011
4211
Cộng545

WAPE = 5 / 5 = 100%, Bias = (4 - 5) / 5 = -20%. Tổng gần đúng, từng ngày gần như đoán mò.

Món bán chậm thì WAPE theo ngày gần như luôn cao, dùng phương pháp nào cũng vậy. Điểm bán thường đặt hàng theo tuần, nên với món này xem tổng theo tuần hoặc xem Bias. Món A thì khác: Bias +41,6% là tín hiệu thật, dự báo đang đặt dư đều đặn.

Đọc bảng độ chính xác dự báo: xem Bias trước, WAPE sau#

Ngưỡng tôi dùng trong bản demo: cảnh báo khi WAPE trên 50% hoặc Bias lệch quá 30%, bỏ qua cặp bán dưới 20 cái trong kỳ. Ba món trên đều vượt ngưỡng WAPE. Món A vượt cả ngưỡng Bias. Món B có Bias +29,3%, vẫn là dự báo cao, chỉ chưa đủ để báo.

Thứ tự đọc tôi dùng:

  1. Bias lệch quá ngưỡng thì xử lý trước, vì nó đi thẳng vào số lượng đặt hàng.
  2. WAPE cao mà Bias nhỏ ở món bán ít: xem lại theo tuần rồi mới kết luận dự báo kém.
  3. Mọi phương pháp đều so với trung bình 28 ngày. Không thắng mốc này thì không đáng dùng.

MA28, SWA8 và Holt-Winters tính thế nào#

  • MA28 lấy trung bình 28 ngày hợp lệ trước kỳ kiểm tra. Mọi ngày trong kỳ dự báo cùng một số.
  • SWA8 lấy trung bình theo thứ trong tuần, trên 8 tuần gần nhất. Một đợt khuyến mãi lọt vào 8 tuần đó sẽ kéo lệch số của thứ đó.
  • Holt-Winters tách số bán thành mức nền, xu hướng và mùa vụ theo thứ, rồi mỗi ngày sửa lại từng phần một chút.
text
Dự báo         = Mức nền + Xu hướng + Mùa vụ của thứ
Mức nền mới    = α × (Bán - Mùa vụ của thứ) + (1 - α) × Mức nền cũ
Mùa vụ thứ mới = γ × (Bán - Mức nền mới) + (1 - γ) × Mùa vụ cũ

Ví dụ mức nền 10, thứ Bảy +4, α = 0,2, γ = 0,1, không xu hướng. Dự báo thứ Bảy là 14, bán thật 18. Mức nền mới = 0,2 × (18 - 4) + 0,8 × 10 = 10,8. Mùa vụ thứ Bảy mới = 0,1 × (18 - 10,8) + 0,9 × 4 = 4,32. Dự báo thứ Bảy tuần sau = 10,8 + 4,32 = 15,1.

α và γ là mức tin vào ngày mới. Code thử 5 giá trị α, 4 giá trị γ, có hoặc không có xu hướng tắt dần, tổng 40 tổ hợp cho mỗi cặp mặt hàng và cửa hàng, rồi giữ bộ có tổng bình phương sai số nhỏ nhất trên dữ liệu cũ. Viết bằng AL, 74 cặp chạy khoảng 10 giây.

Holt-Winters là time series thống kê thuộc họ làm trơn mũ (exponential smoothing). Nó chỉ cộng, trừ, nhân, chia, không gọi model nào, nên không phải AI.

Phương pháp phức tạp hơn thắng trung bình động bao nhiêu#

Bảy cách chạy bằng Python trên cùng dữ liệu, cùng kỳ kiểm tra, bỏ ngày hết hàng nhưng chưa bỏ ngày khuyến mãi. Trần lý thuyết là dự báo bằng chính kỳ vọng của hàm sinh dữ liệu mô phỏng, không mô hình nào tốt hơn được.

Cách dự báoWAPEBias
Trần lý thuyết34,6%+7,9%
Holt-Winters (ETS)37,7%+6,9%
SARIMA37,8%+6,9%
MA2838,7%+6,4%
ETS kết hợp LightGBM39,8%+8,6%
SWA841,2%+9,3%
LightGBM42,9%+10,4%
Lặp lại tuần trước48,6%+4,9%

Holt-Winters chỉ hơn MA28 khoảng 1 điểm, trong khi từ MA28 tới trần chỉ còn khoảng 4 điểm. Nhóm kem cải thiện nhiều hơn (trần 20,2%, Holt-Winters 27,9%, MA28 31,9%) vì dữ liệu mô phỏng cho kem bán mạnh tháng 6 đến 8 rồi giảm sang tháng 9. LightGBM thua vì chỉ có 74 chuỗi, mỗi chuỗi 6 tháng, không có giá, khuyến mãi, ngày lễ. Kết quả này không dùng để hứa với khách, trên dữ liệu thật phải đo lại.

Vì sao phải bỏ ngày hết hàng và ngày khuyến mãi khi chấm điểm#

Ngày hết hàng, tức tồn đầu ngày bằng 0 hoặc âm và cả ngày không bán, bị bỏ khỏi phép chấm, vì không thể trách dự báo sai vào ngày không có hàng để bán. Ngày có dòng Planned Sales Demand của LS đang Enabled cũng bị bỏ. Kết quả trên BC:

Phương phápChưa bỏ ngày khuyến mãiĐã bỏ ngày khuyến mãi
MA2838,7%38,2%
SWA841,2%37,2%
Holt-Winterschưa chạy37,1%

SWA8 lệch nhiều nhất do đợt khuyến mãi tháng 7: khuyến mãi rơi vào thứ nào thì số của thứ đó bị kéo lên suốt 8 tuần sau.

Lý do thứ hai quan trọng hơn khi dự báo đi vào LS Replenishment. Kiểu tính Retail Forecast của LS coi số trong bảng LSC Forecast Entry là mức nền, rồi tự cộng Planned Sales Demand. Ví dụ ngày thường bán 10, ngày khuyến mãi bán 25, Planned Sales Demand cộng 15:

  • Bỏ ngày khuyến mãi khi học: mức nền 10, ngày khuyến mãi tới LS ra 10 + 15 = 25. Đúng.
  • Không bỏ: mức nền bị kéo lên khoảng 12, ngày khuyến mãi tới ra 27, mọi ngày thường sau đó ra 12 thay vì 10. Đặt dư hàng.

Holt-Winters là công thức đệ quy, mỗi bước là một ngày, nên không xóa được ngày khỏi chuỗi. Bản demo thay số bán của hai loại ngày đó bằng trung bình các ngày hợp lệ cùng thứ trong 8 tuần trước. Giới hạn còn lại: bánh hết lúc 14 giờ thì hôm đó vẫn có bán, vẫn tính là ngày bình thường, nhu cầu thật bị đánh giá thấp.

Trước khi đo, kiểm lịch sử bán đã đúng đơn vị tính chưa. Một lần import thiếu cột Unit of Measure Code làm LS báo bán bình quân 0,29 cái/ngày cho một mặt hàng bánh, chi tiết ở bài sáu bẫy khi import tồn đầu kỳ có lot.

Số dự báo đi vào đề xuất bổ sung hàng thế nào#

Trên LS Replenishment, mặt hàng dùng kiểu Retail Forecast thì LS đọc dự báo từng ngày, cộng Planned Sales Demand, rồi trừ tồn. Một dòng trong nhật ký tính của bản demo: tổng dự báo 7 ngày là 24,2, khuyến mãi +150% trong ba ngày nâng lên 38,66, trừ tồn 34, LS đề xuất chuyển 5. Dự báo cao hơn thực tế bao nhiêu thì đề xuất dư bấy nhiêu, nên Bias là con số cần nhìn trước.

Kiểu Average Usage không đọc bảng dự báo mà lấy bán bình quân có trọng số theo Sales Profile, cùng họ trung bình động với MA28.

BC chuẩn có extension Sales and Inventory Forecast. Theo tài liệu Microsoft, extension lấy dòng Sale trong Item Ledger Entries và dùng kết quả để gợi ý đặt mua với nhà cung cấp. Kết quả gộp cho mọi location và variant, nên chuỗi nhiều cửa hàng muốn dự báo riêng từng cửa hàng thì phải tự chia lại. Theo Forecasting API overview, thuật toán bên dưới là ARIMA, ETS, STL, TBATS, cũng là time series thống kê, ETS cùng họ với Holt-Winters. Chữ AI ở tính năng này nói về nơi mô hình chạy, tức Azure AI, nhiều hơn là về loại mô hình.

Đọc tiếp