Skip to contents

Generate a complete life table directly from the fitted parameters of a parametric mortality model. This function evaluates the mortality law at the given ages and passes the resulting death rates (mx) or death probabilities (qx) to LifeTable for further computation of all standard life-table columns (lx, dx, Lx, Tx, ex, etc.).

Usage

LawTable(x, par, law, sex = NULL, lx0 = 1e+05, ax = "andreev_kingkade")

Arguments

x

Numeric vector of ages at the beginning of each age interval. For a full life table, use single-year ages (e.g., 0:110). For an abridged life table, use the lower bound of each interval (e.g., c(0, 1, 5, 10, ..., 110)).

par

The parameters of the mortality model. Can be:

  • A numeric vector containing the coefficients (for a single life table).

  • A numeric matrix or data.frame where each row corresponds to a separate set of parameters (producing multiple life tables). Column names must match the parameter names of the chosen law, as described in the details below.

law

The name of the mortality law to be used (e.g., "gompertz", "makeham"). Run availableLaws to see all options.

sex

Sex of the population. Options are NULL (default), "male", "female", or "total". When specified, the first two entries of the ax column are adjusted using Coale-Demeny coefficients, producing more accurate life-table values at the youngest ages. The adjustment differs slightly between males and females.

lx0

Radix, the starting population (or probability scale) at age 0. Default is 100,000. All subsequent life-table columns (lx, dx, Lx, Tx) are scaled accordingly.

ax

The average number of person-years lived in each age interval by those who die in it, given either as values or as the method that produces them. Accepts two forms:

  • a numeric scalar or vector: a scalar is applied to all intervals, a vector must have the same length as x. A common assumption is ax = 0.5, which places deaths at the midpoint of each interval;

  • a method name, one of "andreev_kingkade" (the default), "cfm", "preston" or "coale_demeny" (see below).

"andreev_kingkade" follows the rule the Human Mortality Database applies to its period life tables (Methods Protocol, version 6, section 7.1): the Andreev-Kingkade (2015) formula sets the value for the first year of life from m0, every other closed interval uses half its length (n/2), and the open interval uses 1/mx. It is the most accurate of the four methods and the one that reproduces the published HMD life tables most closely. Because it produces a numeric ax before the rates are converted, the mx to qx step uses the exact identity qx = n*mx/(1 + (n - ax)*mx), which is the identity the protocol uses (equation 74). The Andreev-Kingkade value is a property of a one-year first interval that starts at birth, so when the first interval is wider or the table starts above age 0 the interval keeps the ordinary midpoint value instead.

The other three methods share the same basis, the standard lifetable identity ax = n + 1/m - n/q under a constant force of mortality (Preston, Heuveline and Guillot 2001, eq. 3.15), and differ in how they treat the first two intervals:

  • "cfm": the identity alone, for every interval;

  • "preston": the identity, with the first two intervals replaced by the Coale-Demeny West separation factors published by Preston et al. (2001), table 3.3, when sex is given;

  • "coale_demeny": the identity, with the first two intervals replaced by the original 1983 Coale-Demeny rule expressed in qx, reproduced by the PAS software, when sex is given.

"preston" and "coale_demeny" agree exactly once mx[1] reaches 0.107, and differ by at most a few thousandths of a year below it. Both coincide with "cfm" when sex is NULL. "cfm" and the Coale-Demeny variants adjust ax after the rates have been converted, so they leave the constant force of mortality conversion in place; only "andreev_kingkade" changes the conversion itself.

A value supplied for the open age interval is kept as given. Everybody alive there dies in that interval, so its own rate implies what the average time lived in it should be (1/mx); a value that differs is reported and left alone, which leaves the ax and mx columns of the table disagreeing at that age, or the model-implied value when close is set. The one exception is a table entered from ex, where the curve being inverted fixes that interval. See Details.

Value

An object of class "LifeTable" containing the following components:

lt

A data.frame with the complete life table, including columns for age interval (x.int), exact age (x), death rate (mx), death probability (qx), person-years lived by decedents (ax), survivorship (lx), death distribution (dx), person-years lived (Lx), total person-years remaining (Tx), and life expectancy (ex).

call

The matched function call.

process_date

Timestamp of when the life table was computed.

Details

This function is designed to work with models that have been fitted externally (e.g., via MortalityLaw or by hand). The par argument must contain the estimated coefficients of the mortality law, and law must be one of the valid codes listed by availableLaws.

The ax argument is passed straight to LifeTable; its default, "andreev_kingkade", is the rule the Human Mortality Database applies to its period life tables (Methods Protocol, version 6; see LifeTable for the alternatives). Because a law is evaluated on a possibly scaled age vector, the first interval is only treated as a one-year interval with the Andreev-Kingkade rule when the ages passed in x really start one year apart.

Important caveat: age scaling during fitting

Several mortality laws (e.g., Gompertz, Makeham) internally scale the age vector during optimisation to ensure numerical stability. If the model was fitted using MortalityLaw over an age range [a, b], the published coefficients correspond to the scaled ages, not the original ages. Consequently, LawTable will only produce valid life tables for ages \(\ge a\) (the lower bound of the fitting range). Attempting to use the same coefficients at younger ages will yield incorrect results (e.g., life expectancy at age 25 will equal that at age 45).

To determine which models apply age scaling, run:


A <- availableLaws()$table
A[, c("CODE", "SCALE_X")]

Models with SCALE_X = TRUE rescale the age vector internally. When using LawTable with such a model, make sure the x argument starts from the same lower age bound used during fitting.

For models that do not scale (e.g., Heligman-Pollard "HP"), this limitation does not apply, and LawTable can be used for any age range.

Matching the coefficients to the model parameters

The coefficients supplied in par are matched to the parameters of the chosen law by name and in any order. For a matrix or a data.frame the column names must therefore be the parameter names of that law (e.g. c("A", "B", "C") for "makeham"); the row names are used as the labels of the resulting life tables and must be supplied. An unnamed vector keeps the positional convention, i.e. the coefficients are read in the order in which the parameters are documented for the law.

See also

LifeTable for constructing life tables from raw mortality data; MortalityLaw for fitting parametric mortality models; availableLaws for the list of implemented laws and their scaling behaviour.

Author

Marius D. Pascariu

Examples

# Example 1 --- Makeham --- multiple life tables from a matrix of parameters

x1 <- 45:100
L1 <- "makeham"
C1 <- matrix(
  c(0.00717, 0.07789, 0.00363,
    0.01018, 0.07229, 0.00001,
    0.00298, 0.09585, 0.00002,
    0.00067, 0.11572, 0.00078),
  nrow = 4,
  dimnames = list(1:4, c("A", "B", "C"))
)

LawTable(x = x1, par = C1, law = L1)
#> 
#> Full Life Tables
#> 
#> Number of life tables: 4 
#> Dimension: 224 x 11 
#> Age intervals: [45,46) [46,47) [47,48) ...   ... [98,99) [99,100) [100,+) 
#> 
#>    LT    x.int   x     mx     qx   ax    lx   dx    Lx      Tx    ex
#>     1  [45,46)  45 0.0077 0.0077  0.5 1e+05  770 99615 2755138 27.55
#>     1  [46,47)  46 0.0083 0.0083  0.5 99230  821 98820 2655523 26.76
#>     1  [47,48)  47 0.0089 0.0089  0.5 98409  875 97972 2556703 25.98
#>     1  [48,49)  48 0.0096 0.0095  0.5 97535  931 97069 2458731 25.21
#>     1  [49,50)  49 0.0103 0.0103  0.5 96604  991 96108 2361662 24.45
#>     1  [50,51)  50 0.0111  0.011  0.5 95613 1054 95086 2265554  23.7
#>  <NA>     <NA> ...    ...    ...  ...   ...  ...   ...     ...   ...
#>     4  [98,99)  98 1.8022  0.948  0.5     0    0     0       0  0.55
#>     4 [99,100)  99 1.9834 0.9958  0.5     0    0     0       0   0.5
#>     4  [100,+) 100 2.1828      1 0.46     0    0     0       0  0.46

# ---- Important note on age scaling ----

# The Makeham model applies internal age scaling during fitting.
# If the coefficients above were estimated over ages 45-100, the life
# table produced by LawTable is valid only from age 45 onward.

# ---- Example 1B: correct usage ----
LawTable(x = x1, par = c(0.00717, 0.07789, 0.00363), law = L1)
#> 
#> Full Life Table
#> 
#> Number of life tables: 1 
#> Dimension: 56 x 10 
#> Age intervals: [45,46) [46,47) [47,48) ...   ... [98,99) [99,100) [100,+) 
#> 
#>     x.int   x     mx     qx   ax    lx   dx    Lx      Tx    ex
#>   [45,46)  45 0.0114 0.0113  0.5 1e+05 1132 99434 2486699 24.87
#>   [46,47)  46  0.012 0.0119  0.5 98868 1180 98278 2387264 24.15
#>   [47,48)  47 0.0127 0.0126  0.5 97688 1232 97072 2288986 23.43
#>   [48,49)  48 0.0134 0.0133  0.5 96457 1286 95814 2191914 22.72
#>   [49,50)  49 0.0142 0.0141  0.5 95171 1343 94499 2096100 22.02
#>   [50,51)  50 0.0151  0.015  0.5 93827 1404 93126 2001601 21.33
#>      <NA> ...    ...    ...  ...   ...  ...   ...     ...   ...
#>   [98,99)  98 0.4847 0.3901  0.5   231   90   186     442  1.92
#>  [99,100)  99 0.5236  0.415  0.5   141   58   111     257  1.83
#>   [100,+) 100 0.5658      1 1.77    82   82   145     145  1.77

# ---- Example 1C: incorrect usage ----
# The code below uses the same coefficients but starts at age 25.
# Because the model was fitted on scaled ages (starting at 45),
# the life table at age 25 will be meaningless (e.g., e25 equals e45).
LawTable(x = 25:100, par = c(0.00717, 0.07789, 0.00363), law = L1)
#> 
#> Full Life Table
#> 
#> Number of life tables: 1 
#> Dimension: 76 x 10 
#> Age intervals: [25,26) [26,27) [27,28) ...   ... [98,99) [99,100) [100,+) 
#> 
#>     x.int   x     mx     qx   ax    lx   dx    Lx      Tx    ex
#>   [25,26)  25 0.0114 0.0113  0.5 1e+05 1132 99434 2486687 24.87
#>   [26,27)  26  0.012 0.0119  0.5 98868 1180 98278 2387253 24.15
#>   [27,28)  27 0.0127 0.0126  0.5 97688 1232 97072 2288975 23.43
#>   [28,29)  28 0.0134 0.0133  0.5 96457 1286 95814 2191902 22.72
#>   [29,30)  29 0.0142 0.0141  0.5 95171 1343 94499 2096089 22.02
#>   [30,31)  30 0.0151  0.015  0.5 93827 1404 93126 2001590 21.33
#>      <NA> ...    ...    ...  ...   ...  ...   ...     ...   ...
#>   [98,99)  98 2.2878      1 0.44     0    0     0       0     0
#>  [99,100)  99 2.4728      1  0.4     0    0     0       0     0
#>   [100,+) 100 2.6729      1 0.37     0    0     0       0     0


# ---- How to check which laws apply scaling ----
A <- availableLaws()$table
A[, c("CODE", "SCALE_X")]
#>                     CODE SCALE_X
#> 1               demoivre   FALSE
#> 2               gompertz    TRUE
#> 3              gompertz0    TRUE
#> 4            invgompertz    TRUE
#> 5                makeham    TRUE
#> 6               makeham0    TRUE
#> 7               opperman   FALSE
#> 8                 thiele   FALSE
#> 9            neggompertz   FALSE
#> 10             wittstein   FALSE
#> 11            steffensen    TRUE
#> 12                 perks    TRUE
#> 13               weibull   FALSE
#> 14              pareto_2   FALSE
#> 15            invweibull    TRUE
#> 16            vandermaen    TRUE
#> 17           vandermaen2    TRUE
#> 18      strehler_mildvan    TRUE
#> 19             quadratic    TRUE
#> 20                 beard    TRUE
#> 21         beard_makeham    TRUE
#> 22             ggompertz    TRUE
#> 23                 siler   FALSE
#> 24                    HP   FALSE
#> 25                   HP2   FALSE
#> 26                   HP3   FALSE
#> 27                   HP4   FALSE
#> 28          rogersplanck   FALSE
#> 29            martinelle   FALSE
#> 30       makeham_logquad    TRUE
#> 31      gompertz_logquad    TRUE
#> 32             carriere1    TRUE
#> 33             carriere2    TRUE
#> 34               kostaki   FALSE
#> 35              kannisto    TRUE
#> 36      kannisto_makeham    TRUE
#> 37 scholey_shifted_power   FALSE
#> 38               scholey   FALSE

# Example 2 --- Heligman-Pollard (no scaling) ---

x2 <- 0:110
L2 <- "HP"
C2 <- c(0.00223, 0.01461, 0.12292, 0.00091,
        2.75201, 29.01877, 0.00002, 1.11411)

LawTable(x = x2, par = C2, law = L2)
#> 'qx' is not closed at the last age; it has been set to 1. That is the usual way to close a life table and is applied here, so closing the input yourself is optional.
#> 
#> Full Life Table
#> 
#> Number of life tables: 1 
#> Dimension: 111 x 10 
#> Age intervals: [0,1) [1,2) [2,3) ...   ... [108,109) [109,110) [110,+) 
#> 
#>      x.int   x     mx     qx   ax    lx   dx    Lx      Tx    ex
#>      [0,1)   0 0.0264 0.0258 0.13 1e+05 2580 97760 7118840 71.19
#>      [1,2)   1 0.0022 0.0022  0.5 97420  217 97312 7021080 72.07
#>      [2,3)   2 0.0013 0.0013  0.5 97203  127 97140 6923768 71.23
#>      [3,4)   3  9e-04  9e-04  0.5 97076   92 97030 6826629 70.32
#>      [4,5)   4  7e-04  7e-04  0.5 96984   72 96948 6729599 69.39
#>      [5,6)   5  6e-04  6e-04  0.5 96912   60 96882 6632651 68.44
#>       <NA> ...    ...    ...  ...   ...  ...   ...     ...   ...
#>  [108,109) 108 1.0784 0.7006  0.5     0    0     0       0  0.91
#>  [109,110) 109 1.1318 0.7228  0.5     0    0     0       0  0.87
#>    [110,+) 110 1.1845      1 0.84     0    0     0       0  0.84

# Because "HP" does NOT scale the age vector, the output is valid for
# any starting age. Compare:
LawTable(x = 3:110, par = C2, law = L2)
#> 'qx' is not closed at the last age; it has been set to 1. That is the usual way to close a life table and is applied here, so closing the input yourself is optional.
#> 
#> Full Life Table
#> 
#> Number of life tables: 1 
#> Dimension: 108 x 10 
#> Age intervals: [3,4) [4,5) [5,6) ...   ... [108,109) [109,110) [110,+) 
#> 
#>      x.int   x     mx     qx   ax    lx  dx    Lx      Tx    ex
#>      [3,4)   3  9e-04  9e-04  0.5 1e+05  95 99953 7032264 70.32
#>      [4,5)   4  7e-04  7e-04  0.5 99905  74 99868 6932312 69.39
#>      [5,6)   5  6e-04  6e-04  0.5 99831  62 99800 6832443 68.44
#>      [6,7)   6  5e-04  5e-04  0.5 99769  53 99743 6732643 67.48
#>      [7,8)   7  5e-04  5e-04  0.5 99716  47 99692 6632901 66.52
#>      [8,9)   8  4e-04  4e-04  0.5 99669  43 99647 6533208 65.55
#>       <NA> ...    ...    ...  ...   ... ...   ...     ...   ...
#>  [108,109) 108 1.0784 0.7006  0.5     0   0     0       0  0.91
#>  [109,110) 109 1.1318 0.7228  0.5     0   0     0       0  0.87
#>    [110,+) 110 1.1845      1 0.84     0   0     0       0  0.84
# Note that e3 = 70.31 in both tables, confirming consistency.