Demand-Forecasting Agent
Agentic ML pipeline for retail demand forecasting
View on GitHubA demand-forecasting system for retail sales data in the M5 canonical format — a sales table (series × time), a calendar, and weekly sell prices. The ML core is built and validated as plain, defensible code first; an agent layer (planner → executor → critic → report) wraps it last. Format-general and threshold-adaptive by design: it ingests any M5-format retail dataset and calibrates its decision thresholds to that dataset's own distribution.
Roadmap
Five phases — each gated by review before proceeding.
Three branch signals over M5; four sub-datasets selected at pattern extremes; calibrated thresholds.
Plain L2 (Ridge regression) baseline per dataset — the number every later model must beat. WMAPE on a rolling-origin holdout, frozen feature set, sparse-series mean fallback.
Per dataset: L2 vs Tweedie vs Poisson on WMAPE, proper time-series holdout, with an explicit leakage check. Quantile models added per B4.
Wrap the working core: planner → executor → critic → report. The critic must actually gate acceptance.
Run the finished agent end-to-end on the held-out sub-dataset D.
Agent architecture
The agent (Phase 4) orchestrates a core that already stands on its own.
Confirms M5 schema: required columns present, dates continuous, no missing crucial fields. Flags problems, does not repair.
Runs EDA, interprets the three branch signals (intermittency, spikes, day-of-week η²), and does preprocessing.
Applies deterministic, documented branch rules — selects which branch applies, does not invent modeling decisions.
WMAPE vs threshold + sanity checks (non-negative forecasts, plausible magnitudes). A model that fails is flagged, not accepted.
Short, structured summary to the user with per-dataset results and branch coverage.
Branch logic
Deterministic, documented rules the executor applies — the agent selects which branch, it does not invent decisions.
Zero-inflated demand; Tweedie's compound Poisson-Gamma form fits, unlike squared error.
Lower-intermittency series don't need Tweedie. Explicit complement of B1.
Not enough signal for a heavy model; knowing when not to use it is deliberate.
Requirement-driven — a range answers a different question than a point.
Selected sub-datasets
Each pick sits at a pattern extreme and stresses one branch. D is held out, frozen until Phase 5.
Phase 2 baseline results
5-fold rolling-origin CV. The bar for Phase 3 is min(baseline, 1.0) — a zero forecast scores exactly 1.0 under WMAPE.
Ridge α=1e4, raw — the fitted floor is a real bar
Ridge α=0.01, log1p — baseline lost to a zero forecast
Ridge α=10, log1p — baseline lost to a zero forecast (n=149, full cell)
Design decisions
Each is documented in the plans and enforced by a test.
The ML core is built and validated as plain, defensible code. The agent wrapper (Phase 4) orchestrates what already works — it is not load-bearing.
Branch cuts are percentiles of each dataset's own distribution, so they adapt to new data. Literature constants (Syntetos–Boylan) stay absolute and cited.
WMAPE is volume-weighted and robust on zero-heavy series. WRMSSE re-imports the squared-error sensitivity that Tweedie avoids — rejected by design.
Dataset D informs no distribution and no threshold. The four sub-datasets are disjoint by construction with symmetric cell exclusions.
Day-of-week explains only ~1% of median item variance (η² ≈ 0.012). The per-series gate was dropped; every series gets calendar features instead.
Validation and the critic flag problems rather than guessing or silently patching. A model that fails the critic is flagged, not accepted.
Tech stack
Thanks for reading. Want to see the rest?
Back to all work