Chain ladder
chain_ladder_fit.RdProjects each origin's latest cumulative value to ultimate with
age-to-age factors estimated from the triangle and a tail factor. The
factors are Mack's weighted regressions: average = "volume" is the
volume-weighted chain-ladder factor (Mack's alpha = 1), "simple" the
mean of the link ratios (alpha = 0) and "regression" least squares
through the origin (alpha = 2). Results match R ChainLadder's
MackChainLadder() and chainladder-python
(validation/reference/reserving_chainladder_r.csv).
Usage
chain_ladder_fit(ptr)
chain_ladder(
triangle,
column = NULL,
average = "volume",
sigma_interpolation = "log-linear",
tail = 1
)Arguments
- ptr
A
ChainLadderFitpointer; used internally.- triangle
A triangle, with any number of segments.
- column
Name of the column to fit; by default the only one.
- average
"volume","simple"or"regression".- sigma_interpolation
How a variance parameter that cannot be estimated (an age with a single link ratio) is filled in:
"log-linear"(regresslog(sigma)on age and extrapolate, the default of R ChainLadder) or"mack"(Mack 1993).- tail
Development past the oldest age: a number, the factor from the oldest age to ultimate (1 means no tail), or a
tail_constant(),tail_curve(),tail_bondy()ortail_log_linear().
Details
Every segment of the triangle is fitted on its own. Per-origin
properties run over the origins of each segment in turn, like the rows
of as.data.frame(), and are named by origin, or by "segment / origin" (key values joined by " / ") when there are several segments;
a single-segment fit has one value per origin.
Development past the oldest age is a tail: a given factor, or one
estimated by tail_constant(), tail_curve(), tail_bondy() or
tail_log_linear() (validation/reference/reserving_tails_python.csv
and reserving_tails_r.csv). A tail attached before the oldest age
replaces the estimated factors from there.
Properties of the fit, per origin: latest, ultimate, reserve; per
link (named "12-24" and so on): ldf (the selected factors, which the
projection uses: the estimated ones, replaced by the tail's from its
attachment age), estimated_ldf (the factors as estimated, before the
tail replaced any), sigma (with unestimable ones interpolated),
std_err; per age: cdf (age to ultimate, including the tail); the
tail: tail (the factor from the oldest age to ultimate),
tail_attachment_age (the age from which ldf holds the tail's
factors; the oldest age when it replaced none), tail_ldf (the factors
past the oldest age, which multiply to tail: one per development
period of the next year and one to ultimate, or a single one for
tail_log_linear()), tail_sigma and tail_std_err (the tail's
variance parameter and standard error, extrapolated log-linearly; 0
without a tail, a factor of 1; a tail below 1 is read where a tail of
1.001 would be, as chainladder-python does); and keys, index (one
row per segment, as a triangle's), origins, development, alpha,
total_ultimate and total_reserve (summed over segments). The
per-link, per-age and tail properties need a single-segment fit: with
several segments use development_frame() (ldf, cdf, sigma and
std_err; the oldest age has the tail as its cdf), totals_frame()
(tail, tail_sigma and tail_std_err) or segment().
as.data.frame() gives one row per segment and origin, totals_frame()
one per segment.
Examples
long <- data.frame(year = c(2020, 2020, 2020, 2021, 2021, 2022),
age = c(12, 24, 36, 12, 24, 12),
paid = c(100, 150, 165, 110, 170, 120))
fit <- chain_ladder(triangle(long, "year", "age", "paid"), tail = 1.05)
fit@ldf
#> 12-24 24-36
#> 1.52381 1.10000
fit@reserve
#> 2020 2021 2022
#> 8.25 26.35 91.20
fit@total_reserve
#> [1] 125.8
chain_ladder(triangle(long, "year", "age", "paid"), tail = tail_bondy())@tail
#> [1] 1.1
# Every line of business at once.
by_lob <- rbind(transform(long, lob = "auto"), transform(long, lob = "home", paid = paid / 2))
fits <- chain_ladder(triangle(by_lob, "year", "age", "paid", keys = "lob"))
fits@reserve
#> auto / 2020 auto / 2021 auto / 2022 home / 2020 home / 2021 home / 2022
#> 0.00000 17.00000 81.14286 0.00000 8.50000 40.57143
as.data.frame(fits)
#> lob origin latest ultimate reserve
#> 1 auto 2020 165.0 165.0000 0.00000
#> 2 auto 2021 170.0 187.0000 17.00000
#> 3 auto 2022 120.0 201.1429 81.14286
#> 4 home 2020 82.5 82.5000 0.00000
#> 5 home 2021 85.0 93.5000 8.50000
#> 6 home 2022 60.0 100.5714 40.57143
totals_frame(fits)
#> lob latest ultimate reserve tail tail_sigma tail_std_err
#> 1 auto 455.0 553.1429 98.14286 1 0 0
#> 2 home 227.5 276.5714 49.07143 1 0 0