Skip to contents

In this article we will walk through the steps of creating a life table from input deaths and population data, including how to extend a life table to a higher open age interval using an iterative method.

Loading data

We begin by loading data for a single location-year. As an example, we will use USA males in 2000 in 5-year age groups from HMD, initially collapsed to a lower open age interval to show the effects of extension later

lt_id_cols <- c("hmd_loc_id", "year", "source_type", "sex")
id_cols <- c(lt_id_cols, "age_start", "age_end")

open_age <- 110

lt <- collapse_open_age(
  lifeTableProcessing::hmd_vr_pop_usa_males_2000, 
  open_age = 70
)

We will also load regression parameters created from HMD life tables so that we can create an initial set of life table parameters at higher ages to iterate

coef_qx_diff <- lifeTableProcessing::hmd_extension_qx_diff
coef_ax_mx <- lifeTableProcessing::hmd_extension_ax_mx
coef_ax_qx <- lifeTableProcessing::hmd_extension_ax_qx

Inital Life Table

From deaths and population, we can create an initial life table using naive assumptions about \(a_x\):

lt[, mx := deaths / population]

lt[, ax := (age_end - age_start) / 2]
demCore::gen_u5_ax_from_mx(lt, id_cols)
#> Rows with age not 0-1 or 1-4 will not be assigned ax values.
lt[is.infinite(age_end), ax := demCore::mx_to_ax(mx, age_end - age_start)]

lt[, qx := demCore::mx_ax_to_qx(mx, ax, age_end - age_start)]
demCore::gen_lx_from_qx(lt, id_cols)
demCore::gen_dx_from_lx(lt, id_cols)
source_type hmd_loc_id year sex age_start age_end deaths population mx ax qx lx dx
VR USA 2000 male 0 1 15729.83 1958928 0.0080298 0.066552 0.0079701 1.0000000 0.0079701
VR USA 2000 male 1 5 2823.68 7841313 0.0003601 1.628388 0.0014392 0.9920299 0.0014277
VR USA 2000 male 5 10 1847.44 10516497 0.0001757 2.500000 0.0008780 0.9906022 0.0008697
VR USA 2000 male 10 15 2553.61 10466468 0.0002440 2.500000 0.0012192 0.9897325 0.0012066
VR USA 2000 male 15 20 9699.37 10381688 0.0009343 2.500000 0.0046605 0.9885259 0.0046070
VR USA 2000 male 20 25 13378.28 9630209 0.0013892 2.500000 0.0069220 0.9839188 0.0068106
VR USA 2000 male 25 30 12621.08 9813310 0.0012861 2.500000 0.0064100 0.9771082 0.0062632
VR USA 2000 male 30 35 15276.72 10341599 0.0014772 2.500000 0.0073589 0.9708449 0.0071443
VR USA 2000 male 35 40 23255.66 11350590 0.0020489 2.500000 0.0101920 0.9637006 0.0098221
VR USA 2000 male 40 45 34060.31 11082786 0.0030733 2.500000 0.0152492 0.9538785 0.0145458
VR USA 2000 male 45 50 45127.00 9810326 0.0045999 2.500000 0.0227383 0.9393327 0.0213588
VR USA 2000 male 50 55 55291.46 8491794 0.0065112 2.500000 0.0320344 0.9179739 0.0294067
VR USA 2000 male 55 60 64450.41 6438883 0.0100096 2.500000 0.0488260 0.8885672 0.0433852
VR USA 2000 male 60 65 78920.52 5123319 0.0154042 2.500000 0.0741648 0.8451820 0.0626827
VR USA 2000 male 65 70 103967.33 4398992 0.0236344 2.500000 0.1115790 0.7824993 0.0873105
VR USA 2000 male 70 Inf 698575.26 9786764 0.0713796 14.009480 1.0000000 0.6951888 0.6951888

Then we can achieve better estimates of \(a_x\) by recalculating \(a_x\) from \(d_x\), recalculating \(d_x\), and iterating until agreement is reached:

lt_ax_prep <- demCore::iterate_ax(lt, id_cols)
#> Iteration 1
#> Number of remaining life tables: 1
#> Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. 
#>  1.51 | 1.51 | 1.51 | 1.51 | 1.51 | 1.51
#> Iteration 2
#> Number of remaining life tables: 1
#> Min. | 1st Qu. | Median | Mean | 3rd Qu. | Max. 
#>  0.06 | 0.06 | 0.06 | 0.06 | 0.06 | 0.06
#> Iteration 3
#> Number of remaining life tables: 0
#> Iterations done
source_type hmd_loc_id year sex age_start age_end age_length deaths population mx ax qx lx dx
VR USA 2000 male 0 1 1 15729.83 1958928 0.0080298 0.066552 0.0079701 1.0000000 0.0079701
VR USA 2000 male 1 5 4 2823.68 7841313 0.0003601 1.463845 0.0014391 0.9920299 0.0014276
VR USA 2000 male 5 10 5 1847.44 10516497 0.0001757 2.447109 0.0008780 0.9906023 0.0008697
VR USA 2000 male 10 15 5 2553.61 10466468 0.0002440 3.145355 0.0012193 0.9897326 0.0012068
VR USA 2000 male 15 20 5 9699.37 10381688 0.0009343 2.753370 0.0046616 0.9885258 0.0046081
VR USA 2000 male 20 25 5 13378.28 9630209 0.0013892 2.550629 0.0069224 0.9839176 0.0068111
VR USA 2000 male 25 30 5 12621.08 9813310 0.0012861 2.511119 0.0064101 0.9771065 0.0062633
VR USA 2000 male 30 35 5 15276.72 10341599 0.0014772 2.603851 0.0073600 0.9708432 0.0071454
VR USA 2000 male 35 40 5 23255.66 11350590 0.0020489 2.657072 0.0101953 0.9636978 0.0098252
VR USA 2000 male 40 45 5 34060.31 11082786 0.0030733 2.665306 0.0152568 0.9538726 0.0145531
VR USA 2000 male 45 50 5 45127.00 9810326 0.0045999 2.645067 0.0227533 0.9393195 0.0213726
VR USA 2000 male 50 55 5 55291.46 8491794 0.0065112 2.656259 0.0320665 0.9179469 0.0294353
VR USA 2000 male 55 60 5 64450.41 6438883 0.0100096 2.660064 0.0489024 0.8885116 0.0434504
VR USA 2000 male 60 65 5 78920.52 5123319 0.0154042 2.655051 0.0743357 0.8450612 0.0628182
VR USA 2000 male 65 70 5 103967.33 4398992 0.0236344 3.953257 0.1153189 0.7822430 0.0902074
VR USA 2000 male 70 Inf Inf 698575.26 9786764 0.0713796 14.009606 1.0000000 0.6920356 0.6920356

Extending the Life Table

Now we focus on extending the life table to the desired open age. We begin by creating an initial set of \(q_x\) values for ages between the input and desired open age using regression parameters based on the difference in logit-transformed \(q_x\) values

lt_extended <- extend_qx_diff(
  lt_ax_prep[!is.infinite(age_end), c(..id_cols, "mx", "ax", "qx")],
  coef_qx_diff,
  lt_id_cols
)
#> Warning in min(age_start): no non-missing arguments to min; returning Inf

#> Warning in min(age_start): no non-missing arguments to min; returning Inf

lt_extended[
  is.na(mx) & age_start >= 5,
  mx := demCore::qx_ax_to_mx(qx, ax, age_end - age_start)
]

demCore::gen_lx_from_qx(lt_extended, id_cols)
demCore::gen_dx_from_lx(lt_extended, id_cols, assert_na = FALSE)
lt_extended[is.na(dx), dx := lx * qx]
sex age_start age_end hmd_loc_id year source_type mx ax qx lx dx
male 0 1 USA 2000 VR 0.0080298 0.066552 0.0079701 1.0000000 0.0079701
male 1 5 USA 2000 VR 0.0003601 1.463845 0.0014391 0.9920299 0.0014276
male 5 10 USA 2000 VR 0.0001757 2.447109 0.0008780 0.9906023 0.0008697
male 10 15 USA 2000 VR 0.0002440 3.145355 0.0012193 0.9897326 0.0012068
male 15 20 USA 2000 VR 0.0009343 2.753370 0.0046616 0.9885258 0.0046081
male 20 25 USA 2000 VR 0.0013892 2.550629 0.0069224 0.9839176 0.0068111
male 25 30 USA 2000 VR 0.0012861 2.511119 0.0064101 0.9771065 0.0062633
male 30 35 USA 2000 VR 0.0014772 2.603851 0.0073600 0.9708432 0.0071454
male 35 40 USA 2000 VR 0.0020489 2.657072 0.0101953 0.9636978 0.0098252
male 40 45 USA 2000 VR 0.0030733 2.665306 0.0152568 0.9538726 0.0145531
male 45 50 USA 2000 VR 0.0045999 2.645067 0.0227533 0.9393195 0.0213726
male 50 55 USA 2000 VR 0.0065112 2.656259 0.0320665 0.9179469 0.0294353
male 55 60 USA 2000 VR 0.0100096 2.660064 0.0489024 0.8885116 0.0434504
male 60 65 USA 2000 VR 0.0154042 2.655051 0.0743357 0.8450612 0.0628182
male 65 70 USA 2000 VR 0.0236344 3.953257 0.1153189 0.7822430 0.0902074
male 70 75 USA 2000 VR NA NA 0.1756747 0.6920356 0.1215731
male 75 80 USA 2000 VR NA NA 0.2674195 0.5704625 0.1525528
male 80 85 USA 2000 VR NA NA 0.3997912 0.4179097 0.1670766
male 85 90 USA 2000 VR NA NA 0.5637259 0.2508331 0.1414011
male 90 95 USA 2000 VR NA NA 0.7277048 0.1094320 0.0796342
male 95 100 USA 2000 VR NA NA 0.8509103 0.0297978 0.0253553
male 100 105 USA 2000 VR NA NA 0.9257056 0.0044425 0.0041125
male 105 110 USA 2000 VR NA NA 0.9627513 0.0003301 0.0003178

Iterate to an optimal extension

With an initial projection of \(q_x\), we can now iteratively solve for the ideal extension by calculating life expectancy from the extended ages and comparing it to the life expectancy at the original open age interval

lt_extended[
  lt_ax_prep[is.infinite(age_end)],
  `:=`(
    terminal_age_start = i.age_start,
    mx_term = i.mx
  ),
  on = lt_id_cols
]

lt_extended[, age_length := age_end - age_start]
lt_extended[, age_end := NULL]
setnames(lt_extended, "age_start", "age")
setnames(coef_ax_qx, "age_start", "age")

iteration_results <- iterate_qx(
  dt = lt_extended,
  ax_params = coef_ax_qx[, -"age_end"],
  id_vars = c(lt_id_cols, "age"),
  n_iterations = 50
)
#> [1] "All column names present"
#> [1] "All column names present"
#> [1] "Variable beta passed gte test"

lt_iterated <- copy(iteration_results[[1]])
iteration_info <- copy(iteration_results[[2]])

setnames(lt_iterated, "age", "age_start")
lt_iterated[, age_end := shift(age_start, n = 1, type = "lead")]
lt_iterated[age_start == max(age_start), age_end := open_age]
setcolorder(lt_iterated, id_cols)
hmd_loc_id year source_type sex age_start age_end mx ax qx lx dx
USA 2000 VR male 0 1 0.0080298 0.066552 0.0079701 1.0000000 0.0079701
USA 2000 VR male 1 5 0.0003601 1.463845 0.0014391 0.9920299 0.0014276
USA 2000 VR male 5 10 0.0001757 2.447109 0.0008780 0.9906023 0.0008697
USA 2000 VR male 10 15 0.0002440 3.145355 0.0012193 0.9897326 0.0012068
USA 2000 VR male 15 20 0.0009343 2.753370 0.0046616 0.9885258 0.0046081
USA 2000 VR male 20 25 0.0013892 2.550629 0.0069224 0.9839176 0.0068111
USA 2000 VR male 25 30 0.0012861 2.511119 0.0064101 0.9771065 0.0062633
USA 2000 VR male 30 35 0.0014772 2.603851 0.0073600 0.9708432 0.0071454
USA 2000 VR male 35 40 0.0020489 2.657072 0.0101953 0.9636978 0.0098252
USA 2000 VR male 40 45 0.0030733 2.665306 0.0152568 0.9538726 0.0145531
USA 2000 VR male 45 50 0.0045999 2.645067 0.0227533 0.9393195 0.0213726
USA 2000 VR male 50 55 0.0065112 2.656259 0.0320665 0.9179469 0.0294353
USA 2000 VR male 55 60 0.0100096 2.660064 0.0489024 0.8885116 0.0434504
USA 2000 VR male 60 65 0.0154042 2.655051 0.0743357 0.8450612 0.0628182
USA 2000 VR male 65 70 0.0236344 3.953257 0.1153189 0.7822430 0.0902074
USA 2000 VR male 70 75 0.0317424 2.631083 0.1476124 0.6920356 0.1021530
USA 2000 VR male 75 80 0.0503577 2.606215 0.2247019 0.5898826 0.1325477
USA 2000 VR male 80 85 0.0803626 2.559480 0.3359285 0.4573349 0.1536318
USA 2000 VR male 85 90 0.1246131 2.469101 0.4736762 0.3037031 0.1438569
USA 2000 VR male 90 95 0.1828248 2.292583 0.6114611 0.1598461 0.0977397
USA 2000 VR male 95 100 0.2402334 2.169472 0.7149857 0.0621065 0.0444052
USA 2000 VR male 100 105 0.2823395 2.113722 0.7778332 0.0177012 0.0137686
USA 2000 VR male 105 110 0.3045864 2.102374 0.8089612 0.0039326 0.0031813

Add New Open Age Interval

Finally, all that remains is to calculate the life table parameters for the new open age interval

lt_final <- rbind(
  lt_iterated,
  lt_iterated[1, ..lt_id_cols][, `:=`(age_start = open_age, age_end = Inf, qx = 1)],
  fill = TRUE
)

demCore::gen_lx_from_qx(lt_final, id_cols)
demCore::gen_dx_from_lx(lt_final, id_cols)
hmd_loc_id year source_type sex age_start age_end mx ax qx lx dx
USA 2000 VR male 0 1 0.0080298 0.066552 0.0079701 1.0000000 0.0079701
USA 2000 VR male 1 5 0.0003601 1.463845 0.0014391 0.9920299 0.0014276
USA 2000 VR male 5 10 0.0001757 2.447109 0.0008780 0.9906023 0.0008697
USA 2000 VR male 10 15 0.0002440 3.145355 0.0012193 0.9897326 0.0012068
USA 2000 VR male 15 20 0.0009343 2.753370 0.0046616 0.9885258 0.0046081
USA 2000 VR male 20 25 0.0013892 2.550629 0.0069224 0.9839176 0.0068111
USA 2000 VR male 25 30 0.0012861 2.511119 0.0064101 0.9771065 0.0062633
USA 2000 VR male 30 35 0.0014772 2.603851 0.0073600 0.9708432 0.0071454
USA 2000 VR male 35 40 0.0020489 2.657072 0.0101953 0.9636978 0.0098252
USA 2000 VR male 40 45 0.0030733 2.665306 0.0152568 0.9538726 0.0145531
USA 2000 VR male 45 50 0.0045999 2.645067 0.0227533 0.9393195 0.0213726
USA 2000 VR male 50 55 0.0065112 2.656259 0.0320665 0.9179469 0.0294353
USA 2000 VR male 55 60 0.0100096 2.660064 0.0489024 0.8885116 0.0434504
USA 2000 VR male 60 65 0.0154042 2.655051 0.0743357 0.8450612 0.0628182
USA 2000 VR male 65 70 0.0236344 3.953257 0.1153189 0.7822430 0.0902074
USA 2000 VR male 70 75 0.0317424 2.631083 0.1476124 0.6920356 0.1021530
USA 2000 VR male 75 80 0.0503577 2.606215 0.2247019 0.5898826 0.1325477
USA 2000 VR male 80 85 0.0803626 2.559480 0.3359285 0.4573349 0.1536318
USA 2000 VR male 85 90 0.1246131 2.469101 0.4736762 0.3037031 0.1438569
USA 2000 VR male 90 95 0.1828248 2.292583 0.6114611 0.1598461 0.0977397
USA 2000 VR male 95 100 0.2402334 2.169472 0.7149857 0.0621065 0.0444052
USA 2000 VR male 100 105 0.2823395 2.113722 0.7778332 0.0177012 0.0137686
USA 2000 VR male 105 110 0.3045864 2.102374 0.8089612 0.0039326 0.0031813
USA 2000 VR male 110 Inf NA NA 1.0000000 0.0007513 0.0007513