The ValuationTables package provides the valuationTable
base class and some derived classes to handle different types of valuation life tables, mainly used for life insurance. Additionally it provides a plot function to compare multiple life tables either directly using the absolute mortalities in log-linear plots or using relative mortalities as percentages of a given reference table.
Provided types of valuation tables are:
valuationTable
valuationTable.period (ages, deathProbs, ..., baseYear=2000)
valuationTable.trendProjection
baseYear + n
is calculated as: \(q_x^{(baseYear+n)} = q_x^{(baseYear)} \cdot e^{-n\cdot\lambda_x}\)
YOB
can be calculated as \(q_x^{YOB} = q_x^{(base)} \cdot e^{-(YOB+x-baseYear)\cdot \lambda_x}\)
valuationTable.ageShift
valuationTable.observed
valuationTable.mixed
valuationTable.improvementFactors
library("ValuationTables")
The package provides several real-life life tables published by census bureaus and actuarial associations around the world. You can use the function valuationTables.list
to list all available datasets (if no argument is given) or all datasets that match the given pattern (wildcard character is *). You can then use valuationTables.load
to load either one single data set or all datasets that match the pattern (if wildcard=TRUE
is given).
# list all available data sets
valuationTables.list()
#> [1] "Austria_Annuities" "Austria_Annuities_AVOe1996R"
#> [3] "Austria_Annuities_AVOe2005R" "Austria_Annuities_EROMF"
#> [5] "Austria_Annuities_RR67" "Austria_Census"
#> [7] "Germany_Annuities" "Germany_Annuities_DAV1994R"
#> [9] "Germany_Annuities_DAV2004R" "Germany_Endowments"
#> [11] "Germany_Endowments_DAV1994T" "Germany_Endowments_DAV2008T"
#> [13] "USA_Annuities" "USA_Annuities_1971IAM"
#> [15] "USA_Annuities_1983a" "USA_Annuities_1994GAR"
#> [17] "USA_Annuities_2012IAM" "USA_Annuities_Annuity2000"
# list all datasets for Austria
valuationTables.list("Austria_*")
#> [1] "Austria_Annuities" "Austria_Annuities_AVOe1996R"
#> [3] "Austria_Annuities_AVOe2005R" "Austria_Annuities_EROMF"
#> [5] "Austria_Annuities_RR67" "Austria_Census"
# Load the German annuity table DAV 2004-R
valuationTables.load("Germany_Annuities_DAV2004R")
#> Loading valuation life table data set 'Germany_Annuities_DAV2004R'
# Load all Austrian data sets
valuationTables.load("Austria_*", wildcard=TRUE)
#> Loading valuation life table data set 'Austria_Annuities'
#> Loading valuation life table data set 'Austria_Annuities_AVOe1996R'
#> Loading valuation life table data set 'Austria_Annuities_AVOe2005R'
#> Loading valuation life table data set 'Austria_Annuities_EROMF'
#> Loading valuation life table data set 'Austria_Annuities_RR67'
#> Loading valuation life table data set 'Austria_Annuities_AVOe1996R'
#> Loading valuation life table data set 'Austria_Annuities_AVOe2005R'
#> Loading valuation life table data set 'Austria_Annuities_EROMF'
#> Loading valuation life table data set 'Austria_Annuities_RR67'
#> Loading valuation life table data set 'Austria_Census'
In the next few sections we will always use some of the provided life tables for demonstration purposes.
The package provides two functions to plot lifetables:
plotValuationTables(table1, table2, ...)
plotValuationTableComparisons(table1, table2, ..., reference=reftable)
Both functionalities are also combined into the S3 plot function for the valuationTable class, so you can usually just call plot on the valuation tables. If the reference
argument is given, plotValuationTableComparisons
is used, otherwise plotValuationTables
is called.
# Log-linear plot comparing some Austrian census tables
plot(mort.AT.census.1951.male, mort.AT.census.1991.male,
mort.AT.census.2001.male, mort.AT.census.2011.male,
legend.position=c(1,0))
# Relative death probabilities in percentage of the latest census
plot(mort.AT.census.1951.male, mort.AT.census.1991.male,
mort.AT.census.2001.male,
reference = mort.AT.census.2011.male, legend.position=c(1,0.75), ylim=c(0,4))
#> Warning in normalize_deathProbabilities(cbind(x = ages(t), y =
#> deathProbabilities(t, : Reference mortality table does not contain ages
#> 101102103104105106107108109110111112 required for normalization. These ages
#> will not be normalized!
For cohort life tables, the plot functions also take either the YOB
or the Period
parameter to plot either the cohort death probabilities for the given birth year or the period death probabilities for the given observation year.
# Comparison of two Austrian annuity tables for birth year 1977
plot(AVÖ1996R.male, AVOe2005R.male, YOB=1977, title="Comparison for YOB=1977")
# Comparison of two Austrian annuity tables for observation year 2020
plot(AVÖ1996R.male, AVOe2005R.male, Period=2020, title="Comparison for observation year 2020")
To obtain death probabilities from all the different types of tables, there are two functions:
deathProbabilities
: Returns the (cohort) death probabilities of the life table given the birth yearperiodDeathProbabilities
: Returns the (period) death probabilities of the life table for a given observation yearvaluationTables.load("Austria_Annuities")
# Get the cohort death probabilities for Austrian Annuitants born in 1977:
qx.coh1977 = deathProbabilities(AVOe2005R.male, YOB=1977)
# Get the period death probabilities for Austrian Annuitants observed in the year 2020:
qx.per2020 = periodDeathProbabilities(AVOe2005R.male, Period=2020)
These functions return the death probabilities as a simple, numeric R vector.
There are two similar functions that return the death probabilities as a period life table object that can be used with all other functions provided by this package:
getCohortTable
: Get a valuationTable
object describing the death probabilities for people born in the given yeargetPeriodTable
: Get a valuationTable
object describing the death probabilities observed in the given year# Get the cohort death probabilities for Austrian Annuitants born in 1977 as a valuationTable.period object:
table.coh1977 = getCohortTable(AVOe2005R.male, YOB=1977)
# Get the period death probabilities for Austrian Annuitants observed in the year 2020:
table.per2020 = getPeriodTable(AVOe2005R.male, Period=2020)
# Compare those two in a plot:
plot(table.coh1977, table.per2020, title="Comparison of cohort 1977 with Period 2020", legend.position=c(1,0))
Not surprisingly, at 43 years the two death probabilities cross, because in 2020 the person born 1977 is 43 years old, so the \(q_x\) refer to the same person. However, for younger ages, the period 2020 probabilities are lower, because the mortality improvement for those younger ages has much less time in the cohort 1977 table. For ages above 43 the cohort table describes the mortality further into the future than 2020, so there is more improvement and thus lower death probabilities for the cohort life table.
function | description |
---|---|
ages(table) |
Returns the vector of ages, for which the life table can provide death probabilities |
getOmega(table) |
Returns the maximum age, for which the life table can provide dath probabilities |
ageShift(table, YOB) |
Returns the age shift for the given year of birth |
baseTable(table) |
Returns the base table, from which the table projects (for cohort tables) |
baseYear(table) |
Returns the year of the base table |
lifetable(table, YOB) |
Returns the cohort death probabilities as a lifetable object for use with the lifecontingencies package |
Period death probabilities are the simplest type of life table, giving the probabilities of death observed during the corresponding year (the “period”). The death probabilities of different ages refer to different persons, being of the corresponding ages in the observation year. All that is needed to create a period life table are the death probabilities and the corresponding ages:
lt = valuationTable.period(name="Sample period lifetable", ages=1:99, deathProbs=exp(-(99:1)/10))
plot(lt, title="Simple log-linear period mortality table")
deathProbabilities(lt)
#> [1] 5.017468e-05 5.545160e-05 6.128350e-05 6.772874e-05 7.485183e-05
#> [6] 8.272407e-05 9.142423e-05 1.010394e-04 1.116658e-04 1.234098e-04
#> [11] 1.363889e-04 1.507331e-04 1.665858e-04 1.841058e-04 2.034684e-04
#> [16] 2.248673e-04 2.485168e-04 2.746536e-04 3.035391e-04 3.354626e-04
#> [21] 3.707435e-04 4.097350e-04 4.528272e-04 5.004514e-04 5.530844e-04
#> [26] 6.112528e-04 6.755388e-04 7.465858e-04 8.251049e-04 9.118820e-04
#> [31] 1.007785e-03 1.113775e-03 1.230912e-03 1.360368e-03 1.503439e-03
#> [36] 1.661557e-03 1.836305e-03 2.029431e-03 2.242868e-03 2.478752e-03
#> [41] 2.739445e-03 3.027555e-03 3.345965e-03 3.697864e-03 4.086771e-03
#> [46] 4.516581e-03 4.991594e-03 5.516564e-03 6.096747e-03 6.737947e-03
#> [51] 7.446583e-03 8.229747e-03 9.095277e-03 1.005184e-02 1.110900e-02
#> [56] 1.227734e-02 1.356856e-02 1.499558e-02 1.657268e-02 1.831564e-02
#> [61] 2.024191e-02 2.237077e-02 2.472353e-02 2.732372e-02 3.019738e-02
#> [66] 3.337327e-02 3.688317e-02 4.076220e-02 4.504920e-02 4.978707e-02
#> [71] 5.502322e-02 6.081006e-02 6.720551e-02 7.427358e-02 8.208500e-02
#> [76] 9.071795e-02 1.002588e-01 1.108032e-01 1.224564e-01 1.353353e-01
#> [81] 1.495686e-01 1.652989e-01 1.826835e-01 2.018965e-01 2.231302e-01
#> [86] 2.465970e-01 2.725318e-01 3.011942e-01 3.328711e-01 3.678794e-01
#> [91] 4.065697e-01 4.493290e-01 4.965853e-01 5.488116e-01 6.065307e-01
#> [96] 6.703200e-01 7.408182e-01 8.187308e-01 9.048374e-01
The observations for the given years
TODO
TODO
TODO
Life tables are simple pass-by-value S4 objects, so copying works by simple assignment.
b=AVOe2005R.female
b@name = "Modified Copy"
# only b is modified, not the original table
b@modification = function(qx) pmax(qx, 0.01)
plot(AVOe2005R.female, b, YOB=2000)
Some uses require post-processing of the death probabilities, like adding a lower bound for the death probabilities. To achive this, all valuationTable
-derived classes have a slot modification
that takes a function that is passed the vector of death probabilities.
lt.mod = valuationTable.period(name="Sample modified lifetable (lower bound of 3%)", ages=1:99, deathProbs=exp(-(99:1)/10), modification=function (qx) pmax(0.03, qx))
plot(lt, lt.mod, title="Original and modified table")
Some uses require post-processing of the death probabilities, like adding a lower bound for the death probabilities. To achive this, all valuationTable
-derived classes have a slot modification
that takes a function that is passed the vector of death probabilities.
AVOe2005R.female.mod = setModification(AVOe2005R.female, modification=function (qx) pmax(0.03, qx));
# Make sure the modified table has a new name, otherwise plots might break
AVOe2005R.female.mod@name = "Modified table (lower bound of 3%)"
plot(AVOe2005R.female, AVOe2005R.female.mod, title="Original and modified table")