Design an elasticity estimation program for a grocery delivery app
You are the data scientist at a grocery delivery app with 40,000 SKUs and about 2 million weekly orders across 60 cities. The pricing team wants SKU-level price elasticities to drive weekly price updates. Historical logs show prices that were set by category managers (they cut prices on slow items and raise them around holidays), plus occasional supplier-driven cost changes. A first regression of log units on log price gave a pooled slope of -0.4.
Explain what is wrong with that number, and design the estimation program: where the price variation comes from, the unit of randomization, the model, how you handle the many SKUs with little data, how you handle substitutes, and what you report to the pricing team.
What is wrong with -0.4. Prices in the logs were set in response to demand: cut when an item is slow, raised at holidays when demand is high. The log price is therefore correlated with the demand shock, and the regression slope picks up the shock as well as the price effect. In this lesson's simulation, a manager raised prices into an unobserved demand shock (correlation of log price and shock 0.85) and the naive slope was -1.087 against a true -2.0 (verified); the bias is the covariance of price and shock over the variance of price, so more data cannot fix it. A pooled -0.4 would also average very different products (staples against indulgences), so it is not a SKU-level answer.
Source of price variation, in order of preference.
- Randomized price tests on a ladder around the current price (for example -10, -5, 0, +5, +10 percent) for a sample of SKUs. The simulated test with 7 price arms and 1,400 store-weeks gave -2.007 with a standard error of 0.030 against a true -2.0 (verified). Keep the tested range as wide as the business will accept; outside it the answer is a guess.
- Instruments or natural experiments where tests are not possible: supplier cost shocks that move shelf price without moving demand directly (first-stage F of 431 and a 2SLS estimate of -2.162 with standard error 0.107, verified). Check the exclusion restriction: costs that co-move with demand (a commodity shortage that also affects shoppers) break it.
- Controls and double machine learning on the observational logs, with SKU, city and week effects and promotion, weather, holiday and competitor-price features. This removes only confounding that you observe; say so (the DML recipe is in Uplift Modeling & Heterogeneous Treatment Effects, not run in this lesson).
Unit of randomization. App users compare prices and a single user may see an item in several places, so randomize at the city-by-week or store-by-week level with a matched-pairs design, or use a switchback by city-time block if supply (drivers, picker capacity) is shared (Advanced Experimentation: Interference, Marketplaces & Platforms). Avoid showing two customers in the same household different prices for the same item. Pre-register the guardrails: conversion, basket size, complaint rate, and delivery-time metrics.
Model. Poisson (log link) or log-log OLS of units on log price, clustered by city and SKU; a Poisson fit is robust to zeros (it gave -1.995 against OLS -2.007 in the simulation, verified). Include controls for promotions and stockouts, and fit a spline or compare a log-linear specification to check the constant-elasticity assumption.
Many SKUs, little data. Estimate elasticities with partial pooling: each SKU's elasticity is drawn from its category-level distribution, so SKUs with sparse variation shrink toward the category mean and well-tested SKUs keep their own value; allow the category mean to depend on price tier, brand and perishability (Bayesian Statistics for Data Scientists). Report intervals, and apply a minimum-evidence rule: below it, the price stays at the category default.
Substitutes. Single-SKU elasticities miss cannibalization. Fit a choice model (MNL or nested logit) within a category, or estimate the effect of each SKU's price on the category basket. In the lesson's MNL a 9-to-8 store-brand cut drew 41 percent of its gain from the firm's own other products (verified), which a SKU-level regression would count as incremental.
What to report. For each SKU: elasticity with an interval, the tested price range, the evidence tier (randomized, instrumented, observational), the implied profit-maximizing price from the markup rule P^{*}=c\varepsilon/(1+\varepsilon) only where the interval stays below -1, and the profit regret if the elasticity is off by 0.5 (in the simulation, assuming -2.5 instead of -2.0 cost 4.0 percent of profit, verified). Update prices inside the tested range, in small steps, and re-measure.
Share this question