Skip to contents

Methods that credit each origin's latest value and an expected ultimate, apriori times the origin's exposure, by how developed the origin is. With q = 1 / cdf the share of the ultimate developed at the origin's latest age:

Usage

expected_loss_fit(ptr)

expected_loss(
  triangle,
  column,
  exposure,
  apriori = 1,
  average = "volume",
  sigma_interpolation = "log-linear",
  tail = 1
)

bornhuetter_ferguson(
  triangle,
  column,
  exposure,
  apriori = 1,
  average = "volume",
  sigma_interpolation = "log-linear",
  tail = 1
)

benktander(
  triangle,
  column,
  exposure,
  apriori = 1,
  n_iters = 1,
  average = "volume",
  sigma_interpolation = "log-linear",
  tail = 1
)

Arguments

ptr

An ExpectedLossFit pointer; used internally.

triangle

A triangle, with any number of segments.

column

Name of the loss column to project.

exposure

Name of the exposure column; each origin's latest observed value is its exposure.

apriori

Expected loss ratio: the expected ultimate per unit of exposure; positive.

average, sigma_interpolation, tail

The development pattern, as in chain_ladder().

n_iters

Number of Bornhuetter-Ferguson steps; a non-negative whole number.

Value

An expected_loss_fit object.

Details

  • expected_loss(): the ultimate is apriori * exposure, whatever has been observed;

  • bornhuetter_ferguson(): the ultimate is latest + (1 - q) * apriori * exposure;

  • benktander(): starting from U(0) = apriori * exposure, U(k) = latest + (1 - q) * U(k - 1) for n_iters steps, so n_iters = 0 is the expected loss method, 1 is Bornhuetter-Ferguson, and many iterations approach the chain ladder. The steps are summed in closed form, so a large n_iters is cheap; where an origin's cdf is below 1/2 they diverge instead.

The development pattern is a chain_ladder() fit of the loss column, with the same average, sigma_interpolation and tail. The exposure (premium, say) is another column of the same triangle: each origin's latest observed cumulative value in the segment fitted, which must be finite and positive. Results match chainladder-python's ExpectedLoss, BornhuetterFerguson and Benktander with sample_weight = premium.latest_diagonal (validation/reference/reserving_expected_loss_python.csv).

Every segment of the triangle is fitted on its own, with its own exposure. Per-origin properties run over the origins of each segment in turn and are named as a chain_ladder_fit's.

Properties of the fit, per origin: latest, exposure, apriori (the expected loss ratio), ultimate and reserve (ultimate - latest; the method's own, not the chain ladder's); ldf and cdf of the development pattern, which need a single-segment fit; chain_ladder (the chain_ladder_fit of the pattern), keys, index, origins, development, total_ultimate and total_reserve (summed over segments). as.data.frame() gives one row per segment and origin with exposure and apriori after the reserve, totals_frame() one per segment with the total exposure.

Errors: an unknown column, an origin without an observed, finite, positive exposure (naming the origin and, with keys, the segment), an apriori that is not finite and positive, or a negative or fractional n_iters.

These are Python's ExpectedLoss, BornhuetterFerguson and Benktander, whose fit() returns an ExpectedLossFit.

See also

cape_cod() to estimate the apriori from the triangle, segment() for one segment.

Examples

long <- data.frame(year = c(2020, 2020, 2021), age = c(12, 24, 12),
                   paid = c(100, 150, 200), premium = c(250, 250, 400))
tri <- triangle(long, "year", "age", c("paid", "premium"))
expected_loss(tri, "paid", "premium", apriori = 0.5)@ultimate
#> 2020 2021 
#>  125  200 

# The 2021 origin is a third developed (cdf 1.5): 200 + (1/3) * 0.5 * 400.
bf <- bornhuetter_ferguson(tri, "paid", "premium", apriori = 0.5)
bf@ultimate
#>     2020     2021 
#> 150.0000 266.6667 
bf@cdf
#> 12-Ult 24-Ult 
#>    1.5    1.0 
as.data.frame(bf)
#>   origin latest ultimate  reserve exposure apriori
#> 1   2020    150 150.0000  0.00000      250     0.5
#> 2   2021    200 266.6667 66.66667      400     0.5

benktander(tri, "paid", "premium", apriori = 0.5, n_iters = 2)@ultimate
#>     2020     2021 
#> 150.0000 288.8889