TL;DR & Quick Summary
When an item runs out, your sales data records what you sold, not what customers wanted. That gap, the lost sales, is invisible in most reports. It also corrupts forecasts: items that run out get under-forecast, so they run out again.
Plain average of sales: understated true demand by 8.2% across 200 simulated items
Dropping stockout days: better, but still 1.3% low, because stock runs out on the busiest days
Censored estimate, which treats stockout days as "at least this much": 0.0% bias on average, and its lost-sales estimate matched the true figure almost exactly
What you need: daily or weekly sales plus a record of when each item was out of stock
Key Takeaway: Before trusting any forecast or reorder point, correct the history for stockouts. Otherwise your best-selling, most-often-short items look less popular than they are.
Get Started: Want your lost sales measured? Schedule a strategy call with Cogniq AI or see our predictive analytics services.
Why Stockouts Hide Demand
On a normal day, sales equal demand. On a day an item runs out, sales stop at the stock you had, while customers keep asking. Statisticians call this censored data: you know demand was at least what you sold, but not how much more.
The damage compounds:
- Sales history understates demand on exactly the items that run out
- Forecasts trained on that history come in low
- Reorder points based on those forecasts are too low
- The item runs out again, and the history gets worse
This is why stockout flags top our data-readiness checklist. It's the single most damaging data problem in inventory forecasting.
Three Ways to Estimate Real Demand
1. Average the sales. What most spreadsheets and many systems do by default. It treats stockout days as normal days, so it always understates demand.
2. Drop the stockout days. Average only days when the item was in stock. Better, but still biased low. Stock tends to run out on the busiest days, so the days left behind are quieter than average.
3. Use a censored estimate. Treat in-stock days as complete observations and stockout days as "demand was at least the units sold". A standard statistical method then finds the demand rate that best explains both. This uses all the information without pretending stockout days were normal.
What the Methods Got Right and Wrong
We tested all three on 200 simulated items, each with a known true demand rate and a weekly replenishment that sometimes ran short, over 180 days. Because the true demand is known in a simulation, we can measure each method's error exactly.
| Method | Average error in estimated demand |
|---|---|
| Average of all sales | −8.2% |
| Average of in-stock days only | −1.3% |
| Censored estimate | −0.0% |
The censored method's estimate of lost units came to 1.01 times the true figure on average, essentially exact.
For a single example item selling about 12 units a day and out of stock on 18 of 180 days (10%):
- True lost sales were 110 units, about 5.2% of real demand
- The censored method estimated 99 units
- At a $25 margin per unit, that's about $2,750 of lost margin on one item over six months
Multiply that across a catalogue and the hidden cost is usually larger than anyone expected.
The Method in Python
For teams who want to run it themselves, the core takes a few lines with SciPy. sales is a daily array of units sold, and stockout is a matching array that's True on days the item ended out of stock.
import numpy as np
from scipy.stats import poisson
from scipy.optimize import minimize_scalar
def censored_demand_rate(sales, stockout):
sales, stockout = np.asarray(sales), np.asarray(stockout, bool)
def neg_log_likelihood(lam):
in_stock = poisson.logpmf(sales[~stockout], lam).sum()
# on stockout days, demand was at least what was sold
out = poisson.logsf(sales[stockout] - 1, lam).sum()
return -(in_stock + out)
return minimize_scalar(neg_log_likelihood, bounds=(0.01, 1e4), method="bounded").x
def expected_lost_units(sales, stockout, lam, kmax=None):
lost = 0.0
for s in np.asarray(sales)[np.asarray(stockout, bool)]:
k = np.arange(s, int(kmax or max(s, lam) * 5 + 50))
p = poisson.pmf(k, lam); p /= p.sum() # demand, given it was at least s
lost += (p * (k - s)).sum()
return lost
This assumes demand follows a Poisson distribution, which fits many items selling a few to a few dozen units a day. For very variable items a negative binomial is better. For seasonal or promoted items, estimate demand in comparable periods rather than across the whole year.
Turning Lost Units Into Money
Lost units aren't lost revenue one-for-one. Some customers buy a substitute you also stock, some wait, and some go elsewhere. Our stockout cost calculator walks through substitution, delayed purchases and customer switching, and needs exactly the lost-units figure this method provides. Combine the two for a realistic cost of stockouts.
What to Do With the Result
- Rebuild forecasts on corrected demand for items with frequent stockouts
- Recalculate reorder points and safety stock from the corrected demand. See safety stock and reorder point
- Rank items by lost margin and fix the top of the list first
- Report lost sales monthly alongside stock value, so the trade-off between holding stock and running out is visible to purchasing and finance
Turning It Into a Business Case
Lost sales are one of the clearest numbers to put in front of a finance team, because they're in money. A simple way to build the case:
- Run the estimate across your catalogue, not just one item, using the last six to twelve months
- Convert lost units to lost margin using each item's margin, then reduce it for substitution, since some customers buy a similar item you also stock
- Rank items by lost margin and look at the top 20. Usually a small share of items accounts for most of the loss.
- Compare with the cost of carrying more stock on those items. If raising the reorder point costs less in holding cost than it recovers in margin, the decision makes itself.
For our example item, $2,750 of lost margin over six months against a few dozen extra units of stock would usually justify a higher reorder point. Across hundreds of items, the same arithmetic often justifies a forecasting project on its own.
Weekly Data and Partial Stockouts
Two practical complications:
- Weekly data. If you only have weekly sales and a weekly stockout flag, the same method works at weekly level, but it's less precise, because a week with a stockout on Friday is treated as fully censored. Daily data, or the number of days out of stock each week, improves the estimate.
- Partial-day stockouts. An item that sells out at 2pm loses the afternoon's demand, but daily sales still show a non-zero number. The censored method handles this correctly as long as the day is flagged as a stockout. Ending the day with zero stock is a reasonable flag.
Questions Finance Will Ask
- "How do you know customers wanted it?" Because the estimate uses the item's demand on in-stock days, adjusted for the fact that stockouts happen on busy days. It doesn't invent demand. It infers it from the item's own history.
- "Didn't they just buy something else?" Sometimes. That's why lost units are reduced for substitution before being turned into lost margin.
- "How accurate is this?" In our tests on 200 items with known true demand, the estimate of lost units was correct on average. For a single item it was within about 10%.
When You Don't Have Stock Records
Without stock-on-hand history, you can sometimes infer stockouts from patterns: an item that normally sells every day suddenly shows zero for several days, then resumes after a delivery. This is less reliable and can confuse genuine lulls with stockouts. If it matters to the business, start recording end-of-day stock levels now. Most inventory systems can export them, and a few months of history makes a large difference.
How This Fits a Forecasting Project
Correcting for stockouts is usually one of the first and highest-value steps in a predictive analytics project. It's cheap to do, it improves every downstream forecast, and the lost-sales figure it produces often makes the business case for the rest of the project on its own.
Making It Routine
The estimate is most useful as a monthly number, not a one-off study. Run it automatically as part of your reporting: lost units and lost margin by item and location, the top 20 items by lost margin, and the trend over time. When a reorder point or forecast change works, the lost-sales figure falls. When it doesn't, it's the first number to show it.
Common Mistakes
- Treating zero sales as zero demand on days the item wasn't available
- Counting only full-day stockouts. An item that runs out at noon also lost afternoon demand. Daily data can't fully see that, so hourly data or end-of-day flags help.
- Ignoring the knock-on effect on substitutes. When one item runs out, its substitutes sell more than normal, which inflates their apparent demand.
- Correcting once and forgetting. Stockouts keep happening, so the correction belongs in the regular data pipeline, not a one-off analysis.
Conclusion
Every stockout leaves a gap between what you sold and what customers wanted, and that gap quietly lowers your forecasts and reorder points. A plain average of sales understated demand by about 8% in our tests, and dropping stockout days still left it about 1% low. A censored estimate removed the bias and measured lost sales almost exactly. Correct the history, put a number on the lost margin, and rebuild forecasts on real demand.
Schedule a strategy call with Cogniq AI to measure lost sales across your catalogue, or explore our predictive analytics services.


