Skip to content

CONCEPT Cited by 1 source

Counterfactual stockout demand modeling

The censored-observation problem

When an article stocks out mid-period, the only data you observe is "sold X, where X ≤ on-hand inventory". The true demand — what customers would have bought if inventory were unlimited — is censored by the stockout. You see the truncated observation, not the underlying demand.

This causes two failure modes in naive downstream systems:

  • Forecasters trained on stockout-truncated data learn that demand is low in stockout periods (it's not — fulfilled demand was low because supply was low).
  • Simulators that treat stockout-period demand as zero underestimate the cost of stockouts and over-recommend low-inventory policies.

Classical inventory textbooks handle this via the censored-likelihood correction in demand estimation. Zalando's ZEOS takes a different approach: simulate the counterfactual demand explicitly during DES.

The counterfactual approach

Inside a DES run:

  1. Sample weekly demand from the probabilistic forecast — this is the unconstrained demand for this alternate timeline.
  2. Fulfil from on-hand inventory — this is the realised sales, always ≤ unconstrained demand.
  3. Record the unfulfilled (counterfactual) portion as lost sales — not zero, but the actual gap between unconstrained demand and on-hand inventory.
  4. Use the counterfactual gap to compute C_lost sales — weighted by return rate to get realised lost margin (a lost sale that would have been returned anyway isn't really lost).

The counterfactual demand isn't observed in historical data; it's sampled in simulation from the forecast distribution. This only works because the DES is driven by a probabilistic forecast — a point-forecast DES would have no uncertainty to counterfactually sample against.

Verbatim

"Counterfactual Modeling: We handle the 'unseen' — like demand that would have happened during a stock-out — using probabilistic distributions rather than rough guesses."

Why "rough guesses" don't work

Alternatives Zalando rejects:

  • Treat stockout demand as zero — underestimates stockout cost massively.
  • Truncate simulation on stockout — the run is aborted at the first stockout; biases cost estimates toward short-run outcomes.
  • Assume historical demand continued — ignores the scenario's specific stochastic realisation; defeats the point of Monte Carlo sampling.
  • Interpolate from neighbouring periods — introduces lag / smoothing bias.
  • Zero out the week — same as option 1 in effect.

Sampling from the probabilistic forecast distribution is the statistically-principled answer: the counterfactual demand is exactly what the forecast predicted was plausible for that period, just not observed because inventory ran out.

Composition with the cost model

C_lost sales in the Zalando objective is the margin loss adjusted by return rates. Breaking this down:

  • Unfulfilled demand per scenario = max(0, sampled_demand − on_hand).
  • Per-unit margin = price − cost of goods.
  • Expected return rate = empirical per-article return rate.
  • Realised lost margin per unfulfilled unit = margin × (1 − return_rate) — the units that would have been returned don't count as lost margin.
  • C_lost sales = Σ(unfulfilled_demand × realised_lost_margin) across weeks.

The return-rate adjustment is a load-bearing detail: in fashion commerce, return rates vary widely (some categories 15%, some 60%), and a naive lost-sales-as-full-margin calculation would over-penalise high-return categories.

Tradeoffs

  • Depends on forecast quality. If the probabilistic forecast over-estimates demand, counterfactual sampling over-penalises stockouts — leading to over-ordering. If it under-estimates demand, the DES under-represents stockout costs and the optimiser recommends under-ordering.
  • Only available with probabilistic forecasts. Point forecasts can't produce counterfactual samples; you'd need to pair with a separate uncertainty model.
  • Correlated with demand realisation. The sampled counterfactual demand for a stocked-out week isn't independent of the stock-out-triggering demand — they're drawn from the same underlying distribution. Zalando sidesteps this by sampling the full weekly demand first, then computing fulfilment as min(demand, on_hand) — the counterfactual is just the tail beyond on-hand.

Canonical instance (Zalando ZEOS)

  • systems/zeos-replenishment-recommender — inside the 12-week DES, stockout weeks sample counterfactual unfulfilled demand from the forecast distribution; lost-sales cost is computed on the counterfactual gap weighted by return rate.

Seen in

Last updated · 428 distilled / 1,221 read