Halley’s life table and the hazard rate (1693)#

In 1693 Edmond Halley used five years of births and burials from Breslau to tabulate how many of 1000 one-year-olds were still alive at each later age. The fall from one age to the next is the probability of dying in that year, the first estimate of what reliability engineers call the hazard rate (life_table_hazard()). Halley’s hazard is high in infancy, lowest around age ten and rises steadily with age: the bathtub curve (bathtub_hazard()) that describes many machines as well as people.

import matplotlib.pyplot as plt
import numpy as np

from engineeringkit.reliability import bathtub_hazard, life_table_hazard

Halley’s table#

Persons living at each age from 1 to 84, as printed in the Philosophical Transactions (time unit: years).

# fmt: off
alive = [
    1000, 855, 798, 760, 732, 710, 692, 680, 670, 661, 653, 646, 640, 634,
    628, 622, 616, 610, 604, 598, 592, 586, 579, 573, 567, 560, 553, 546,
    539, 531, 523, 515, 507, 499, 490, 481, 472, 463, 454, 445, 436, 427,
    417, 407, 397, 387, 377, 367, 357, 346, 335, 324, 313, 302, 292, 282,
    272, 262, 252, 242, 232, 222, 212, 202, 192, 182, 172, 162, 152, 142,
    131, 120, 109, 98, 88, 78, 68, 58, 50, 41, 34, 28, 23, 20,
]
# fmt: on
ages = np.arange(1, 85)
hazard = life_table_hazard(ages, alive)
young = int(ages[np.argmin(hazard)])
print(f"hazard at age 1: {hazard[0]:.3f}/yr, lowest {hazard.min():.4f}/yr at age {young}, at age 80: {hazard[79]:.3f}/yr")
hazard at age 1: 0.157/yr, lowest 0.0093/yr at age 12, at age 80: 0.187/yr

A bathtub hazard through the same data#

Infant mortality decaying over a few years, a constant floor and a wear-out term growing as a power of age, fitted by eye.

h = bathtub_hazard(ages + 0.5, early_scale=0.2, early_rate=0.8, random_rate=0.008, wear_scale=2.5e-11, wear_power=5.5)
fig, ax = plt.subplots(figsize=(6.5, 3.8))
ax.semilogy(ages[:-1] + 0.5, hazard, "o", ms=3, label="Halley 1693 (Breslau)")
ax.semilogy(ages + 0.5, h, label="bathtub model")
ax.set(xlabel="age [years]", ylabel="hazard rate [1/year]", title="The human bathtub curve")
ax.legend()
fig.tight_layout()

# The hazard falls through childhood, then rises: a bathtub, not a constant.
assert hazard[0] > 5 * hazard.min() and hazard[78] > 5 * hazard.min()
assert 5 <= young <= 20

plt.show()
The human bathtub curve

Total running time of the script: (0 minutes 0.041 seconds)

Gallery generated by Sphinx-Gallery