Demand unconstraining
How airlines recover the demand they never saw, and what it is worth.
Once a flight or fare class closes, later requests vanish from the data, so the busiest departures record the booking limit, not the demand. This page builds a history where true demand is known, recovers it five ways, then turns it into spill, recapture and the case for a bigger aircraft. The theory is in Revenue Management 101, Chapter 02.
Recovering demand from censored bookings
120 departures of one daily flight. Each has a true demand, drawn from the distribution you set, and a booking limit between 60% and 100% of capacity. Requests arrive along a booking curve; once a departure's bookings reach its limit it closes, and the data collection point (DCP) where it was first seen closed is recorded.
The history: what was recorded, and what was lost
Tap a departure to open it belowFive estimates against the truth
| Method | Mean | ErrorErr. | Std devSD | ErrorErr. | Miss per closed dep.Miss |
|---|
How each method holds up as more departures close
For each share of closed departures, the booking limits are tightened until exactly that share of departures hits its limit, on 40 fresh histories with your mean and variability. The chart shows the average error of each method against the true value.
Spill, recapture and aircraft size
With the demand unconstrained, the question turns around: for a flight with this demand, how many passengers will a given aircraft carry, how many will it turn away, and how much of that comes back on the airline's other flights? The normal spill formula answers it, and running it across real seat counts shows where a bigger aircraft stops paying for itself.
Unconstrained demand per departure
Aircraft
Revenue (illustrative)
Recapture is the share of turned-away passengers who book another flight of the same airline instead of going to a competitor.
Passengers and spill by aircraft size
Per departure, for the demand you set
Revenue per departure by aircraft size
Including recaptured passengers, at the fare you set
Real aircraft, side by side
Seat counts from published cabin layouts| Aircraft | Seats | PassengersPax | Load factorLF | Spill | Spill rateRate | Revenue keptRevenue | Gain vs smallerGain | Layout source |
|---|
How it works
Background
An airline only records the bookings it accepted. Once a flight or a fare class closes, every later request disappears from the data, so on the busiest departures the history shows the booking limit, not the demand. Forecasts built on that history come out too low, and fleet decisions built on those forecasts put too few seats where they are needed.
Why bookings are censored
A booking record is what the airline sold, not what customers asked for. While a flight or fare class is open, every request that fits becomes a booking. Once its bookings reach the booking limit, later requests are turned away and leave no trace in the data (or at best a search log that is hard to tie to one flight). Statisticians call the resulting observation censored: for a closed departure you know demand was at least the limit, not what it was. Averaging those numbers as if they were demand biases the forecast down. A lower forecast protects fewer seats for later passengers or plans fewer seats in the first place, the flight closes earlier, and next season's data is censored even more. Revenue Management 101, Chapter 02 calls this the unconstraining problem.
The synthetic history
Each of the 120 departures gets a true demand D, drawn either from a normal distribution with the mean and variability you choose (variability is the standard deviation as a share of the mean, rounded to whole passengers and floored at zero) or from a Poisson distribution, whose standard deviation is fixed at √mean. Its booking limit L is drawn uniformly between 60% and 100% of capacity: on some days revenue management holds back more seats for later, higher fares, and the seats open to this demand change. Each request arrives a random number of days before departure: 60% follow a leisure pattern (gamma distribution, mean 50 days) and 40% a business pattern (exponential, mean 8 days), with no request earlier than 180 days out. Bookings are observed at DCPs 120, 90, 60, 45, 30, 21, 14, 7, 3, 1 and 0 days before departure. If D ≥ L, the departure closes: its recorded bookings are L and the closure DCP is the first snapshot at which bookings had reached L. The history is generated from seed 20260928; the same seed with the same mean and variability always gives the same true demand, whatever the capacity, so the capacity slider only changes what gets recorded.
The five methods
Notation: xj is the recorded final bookings of departure j; Lj its limit; μ and σ the mean and standard deviation being estimated; φ and Φ the standard normal density and distribution function.
- Naive takes the recorded bookings as demand. It is what a system does if it ignores closures.
- Mean imputation (Weatherford and Pölt's "naive #3") replaces each closed observation by the average of the open departures when that average is higher: x̂j = max(Lj, mean of open departures) It rarely changes anything on flight-level data. The departures that stayed open are the ones with low demand, so their average sits below almost every limit that was hit; the method only helps when some limits are well below typical demand.
- Booking-curve projection uses the time of closure. From the departures that stayed open it estimates fk, the share of final bookings usually in by DCP k. A departure that closed by DCP k had Lj bookings by then, so its demand is projected as x̂j = Lj / fk Because the closure happened some time before the DCP at which it was seen, this errs slightly low. It is the only method here that uses the booking curve, which is why it is the most accurate one departure by departure.
- Expectation-maximisation (EM) assumes demand is normal and finds the μ, σ that best explain both the open observations and the fact that the closed ones exceeded their limits. It alternates two steps until they stop moving. E-step, for each closed departure with z = (Lj − μ) / σ and h = φ(z) / (1 − Φ(z)): E[D | D ≥ Lj] = μ + σh E[D² | D ≥ Lj] = μ² + σ² + σ(Lj + μ)h M-step: the new μ is the average of the open observations and the conditional means; the new σ² is the average of the squares and conditional second moments, minus μ². This is the maximum-likelihood estimate for censored normal data (Dempster, Laird and Rubin, 1977).
- Projection detruncation (Hopperstad, at Boeing) also iterates, but replaces each closed observation by a single point: the value that splits the demand above the limit in the ratio τ = 0.5, that is the median of the tail rather than its mean: x̂j = μ + σ Φ−1(1 − τ(1 − Φ(z))) then recomputes μ and σ from the completed sample and repeats. The tail median is below the tail mean, and single imputed points carry no spread, so each round shrinks σ a little; the bias grows with the share of closed departures. A smaller τ offsets it.
The table's "miss per closed departure" is the average absolute gap between a method's estimate for a closed departure and its true demand (for EM, the estimate is the conditional mean above). The sweep repeats everything on 40 new histories per level, with common random numbers across levels, so the lines differ only because more departures close.
Spill and recapture
For a flight with unconstrained demand D ~ Normal(μ, σ) and C seats, with z = (C − μ) / σ, the expected number of passengers turned away is
Spill(C) = E[max(D − C, 0)] = σ [φ(z) − z(1 − Φ(z))]Expected passengers are μ − Spill(C), the load factor is that divided by C, and the spill rate is Spill(C) / μ. A share r of spilled passengers is recaptured on the airline's other flights, so the revenue the airline keeps is fare × (passengers + r × spill) and the revenue lost is fare × (1 − r) × spill. One more seat is worth fare × (1 − r) × P(D > C) per departure: the chance the flight is full is the only time the extra seat sells. That value falls quickly past mean demand, which is why the gain from each step up in aircraft size shrinks. Upgauging pays off when the bigger aircraft's extra trip cost is below the "gain vs smaller" in the table; trip costs are not modelled here.
From unconstrained demand to forecasts and fleet assignment
Unconstraining sits at the start of both chains. In revenue management, the unconstrained history (by fare class, by DCP) is what the forecaster learns from; the forecasts then set the protection levels and booking limits of EMSR-b or the bid prices of network control, and the pickup forecasts assume their history is demand. Skip the step and the system under-protects, closes low fares on the wrong days and keeps censoring its own data. In network planning, fleet assignment compares, for every flight, the cost of each aircraft type with the revenue it would lose to spill: exactly the calculation in Part 2, with recapture reducing the loss (Network Planning 101, Chapter 05). Feed it recorded bookings instead of unconstrained demand and the busiest flights look like they fit on the aircraft they already have, so the model never upgauges them.
Sources
Methods: L. Weatherford and S. Pölt, "Better unconstraining of airline demand data in revenue management systems for improved forecast accuracy and greater revenues", Journal of Revenue and Pricing Management 1(3), 2002, which compares the naive, mean imputation, booking profile, projection detruncation and EM methods; P. Guo, B. Xiao and J. Li, "Unconstraining methods in revenue management systems: research overview and prospects", Advances in Operations Research, 2012 (open access), which finds EM the most accurate and robust; K. Talluri and G. van Ryzin, The Theory and Practice of Revenue Management (Springer, 2004), chapter 9. Spill: M. Z. F. Li and T. H. Oum, "Airline spill analysis – beyond the normal demand", European Journal of Operational Research 125(1), 2000. Seat counts (checked 28 September 2026, stored in unconstraining.json): Alaska Air Group current fleet for the E175 (76 seats, Horizon and SkyWest), 737-8 (159, Alaska), A321neo (189, Hawaiian) and 787-9 (300, Hawaiian), page dated 27 August 2025; Delta's A220-300 page (130 seats).
Limitations
- The demand history, booking curve, booking limits, fares and recapture rates are illustrative assumptions, not estimates from any airline.
- Demand in the history is identically distributed across departures: no seasonality, day-of-week pattern or trend. Real unconstraining works on groups of comparable departures, often by fare class and DCP, with far fewer observations per group.
- Turned-away requests vanish here. In reality some buy up to an open higher fare or move to another flight (sell-up and recapture), which unconstraining at the fare-class level has to separate from true demand for the closed class.
- EM and projection detruncation assume normal demand; the spill formula does too. It is a good approximation for demand of a hundred or more; for small numbers, or skewed demand, Li and Oum show the normal spill model can be off.
- The spill model treats one flight's total demand against total seats. The seat counts include premium cabins, and a real comparison would spill by cabin. Trip costs, crew, airport slots and the rest of the fleet assignment are left out.
This is a personal project and isn't affiliated with any airline.