Mortality Pullforward Explorer

COVID disproportionately killed people who were already close to dying. This tool lets you set how far into the future those deaths were “pulled from,” and instantly see what that implies for the life expectancy of the people who survived. Inputs are on the left — optionally segmented by age band and sex — and the view controls sit above the results.

Focus cohort — tiles & charts

Male, age 65

Summary table shows

LE gained by survivors
Equiv. mortality multiplier
flat qx scaling matching survivors’ LE
LE before COVID
SSA 2019 baseline
LE for survivors
after removing pulled-forward deaths
Survived COVID
share of the original cohort

The assumption: pullforward curve f(t)

Share of each future year’s deaths that instead happened during COVID.

The result: survivor mortality vs the baseline table

Ratio of the survivors’ death rate to the baseline rate. Below 1.0 means survivors are healthier than the table; it returns to 1.0 once the pullforward window has passed.

View chart data as a table (first 20 years)

Death distribution: original cohort vs survivors

Probability of dying in each future year. Pulled-forward deaths are removed from the early years, shifting the survivors’ curve to the right.

All cohorts under these assumptions

Each cohort uses the inputs of the segment it belongs to. The highlighted row is your focus cohort.

How the model works — the four steps

The model asks one question: if COVID’s victims were mostly people who were going to die soon anyway, how much healthier is the surviving population? It answers in four steps, computed independently for each starting age and sex.

Step A — When would the cohort have died anyway?

From the SSA 2019 period life table, compute the probability that a cohort member dies in each future year t. These are unconditional probabilities — they sum to exactly 100% because everyone eventually dies.

d(t) = S(t−1) × qx(age + t − 1),   where S = probability of surviving to year t

Step B — Which of those deaths did COVID pull forward?

This is the assumption you control, separately for each segment (age band, and optionally sex). f(t) is the share of year-t deaths that instead happened during COVID. The peak fraction sets its height at t=1; the shape and grade-out set how fast it fades for deaths further in the future. A cohort uses the inputs of the segment containing its age at the end of COVID. Grade-out 0, peak 0%, or unticking “active” all mean no pullforward for that segment.

linear:      f(t) = peak × max(0, 1 − (t−1) / grade_out)
step:        f(t) = peak  for t ≤ grade_out, else 0
exponential:  f(t) = peak × e−decay × (t−1)

Note the difference between linear and step: linear starts at the peak and ramps straight down to zero at the horizon (halfway out, only half the peak effect applies), while step applies the full peak effect to every year inside the horizon. “Everyone who would have died within G years died during COVID instead” is the step shape with peak = 100% — but note that if the horizon covers a cohort’s whole remaining lifetime, that setting leaves no survivors and the post-COVID results are undefined.

Step C — What does the surviving population look like?

Remove the pulled-forward deaths from each year and renormalize. The removed mass is the share of the cohort that died during COVID; what remains is the survivors’ death distribution.

g(t) = d(t) × (1 − f(t)) / Z,   where Z = Σ d(t)(1−f(t)) = share who survived COVID

Step D — What does that imply for mortality and life expectancy?

Convert g(t) back into annual death rates for survivors, and compare them to the baseline table. The ratio is the mortality multiple — below 1.0 means the survivors are healthier than the table says, because the frailest members were culled. Life expectancy is the area under the survival curve; the headline number is survivors’ LE minus baseline LE.

multiple(t) = effective_qx(t) / qx_baseline(t),   LE = Σ S(t)

Mortality improvement (the baseline itself gets better)

By default the model assumes mortality keeps improving 1% per year at every age (people have historically kept getting healthier). Projection year t uses qx × (1 − rate)t−1, compounding from 2022. Both the baseline LE and the survivors’ LE include it, so the headline LE change still isolates the pullforward effect. You can set a different flat rate, turn it off, or import a CSV of rates by age (1D) or by age and calendar year (2D) from the sidebar. Improvement applies to all segments.

The equivalent mortality multiplier

A second way to express the survivors’ advantage: the single flat percentage applied to the entire baseline qx table that would produce the same life expectancy the survivors have. For example 92% means “the survivors’ LE gain is what you’d get by cutting mortality 8% at every age, forever.” It is found by bisection and is exact to ~1e-6 years.

Reading the outputs

  • The effect is largest for older cohorts: more of their near-term deaths fell inside the pullforward window.
  • The multiple returns to 1.0 at the grade-out horizon — the model assumes no lasting health advantage, only selection.
  • The math mirrors the Python code in mortality_model/. Each cohort depends only on its own segment’s inputs, so the command in the sidebar reproduces the focus cohort exactly; run it once per segment (changing --age/--sex and the values) to cover all segments.