← Back to the full chapter
Lesson

2. Build a table of opportunities, including non-purchases

Model demand, separate the causal response, and optimise within supported limits.

3 min readApplied extensionUpdated
Read source ↗

Transactions alone miss people who saw the price and chose not to buy. Build a row for every eligible product-market-period, using posted-price and availability logs to create zero-sales rows. A missing row is not automatically zero demand.

FieldRequired meaning
sku_id, market_id, decision_at, horizon_endThe decision unit and the interval governed by the price
posted_price, effective_paid_price, currencyPrice shown, price paid after promotions, and consistent monetary units
price_valid_from, price_valid_toActual duration of exposure to each price; split a day when price changes
eligible_exposure, exposure_definitionEligible visits, offers shown, or hours of availability; state the denominator
units_sold, orders, returnsDistinct outcome definitions, with arrival and maturity timestamps
inventory_start, replenishment, stockout_atCapacity and evidence that observed sales were censored
unit_cost_snapshot, fulfillment_cost, fee_rulesCosts known at decision time; reconcile realised costs afterwards
promotion, placement, campaign_assignmentDiscounts, visibility and concurrent interventions
competitor_snapshot_at, competitor_price, competitor_availabilityComparable product, collection time and missing/stale indicators
policy_version, experiment_id, assignment_probabilityHow assignment was selected; retain the full available action set and any later override
event_at, available_at, snapshot_versionWhen a fact occurred, when the service could know it, and which revision was used

Measure exposure carefully. For visit-level conversion, a customer who does not buy is a valid negative example. For aggregate counts with unequal exposure, a GLM can use a log-exposure offset. The scikit-learn Poisson example shows the related rate-target and exposure-weight set-up. Zero exposure means no chance to observe demand and cannot go through log(0).

Exposure can itself respond to price. Search placement, traffic or customer visits may change after a price change. Conditioning on that realised exposure can hide part of the total price effect. State whether you estimate conversion given exposure or total period sales. For a total effect, use pre-change exposure forecasts or model traffic jointly.

Sales are not demand during a stockout. Selling the last ten units tells you demand was at least ten, not exactly ten. Keep censored periods and mark them. When they matter, use a censored likelihood or an availability-aware choice/demand model. An uncensored subset is fine for a narrow first baseline if you state its selection limits. Dropping stockouts can leave mostly low-demand periods. Availability also changes substitution across products, as Conlon and Mortimer show.

Check support for inventory levels too. If comparable observations were always capped at ten units, they cannot show the demand tail needed to value an inventory of twenty without extra assumptions. Lower-stock decisions may need the tail only up to their own cap. Mark model-based extrapolation clearly and abstain when the needed tail or censoring assumptions are unvalidated.

Include day of week, holidays, seasonality, item age, category, store and lagged demand, using only information available before the recommendation. Compute rolling features separately inside each validation history. A future realised competitor price, end-of-day inventory, post-change page views or a future return flag is not a pre-decision feature. Event time and availability time must both come before the decision: a backfilled Monday transaction first loaded on Wednesday was unavailable to Tuesday's recommendation.

Promotions, loyalty benefits and offer recommendations change the effective price. Track them together, including who funds a discount. Optimising posted price and discount separately can spend the same margin twice. Cross-item prices and availability matter for substitutes and complements, so begin with an isolated category and test that assumption.

Something unclear or out of date? Suggest a correction ↗

Find your next idea

Loading local search…

Search is built from this edition. No account needed.