Fit a Bornhuetter-Ferguson (1972) projection from a "Triangle"
object. The BF estimator blends the observed cumulative loss for
each cohort with an a priori expected loss ratio (ELR) applied to
the cohort's ultimate premium, weighted by the expected unemerged
fraction \(1 - q_i\):
$$\hat L_{ult, i}^{BF} = L_{obs, i} + (1 - q_i) \cdot \mathrm{ELR}_i \cdot E_i^{ult}$$
where
\(L_{obs, i}\): cohort \(i\)'s observed cumulative loss at its latest observed development period.
\(q_i = L_{obs, i} / \hat L_{ult, i}^{CL}\): the expected emerged fraction, equivalent to the inverse of the cumulative loss development factor (LDF) for cohort \(i\).
\(\mathrm{ELR}_i\): the user-supplied a priori expected loss ratio for cohort \(i\) (
priorargument).\(E_i^{ult}\): cohort \(i\)'s ultimate premium, projected via chain ladder on the
premiumcolumn.
This is a peer worker alongside fit_cl() / fit_ed() / fit_loss().
Standalone for the BF recipe – composition with fit_ratio() is not
part of this worker. Point projection is always computed; bootstrap
SE / CI is opt-in via bootstrap = TRUE (Phase 3b). Closed-form
Mack (2008) MSEP is not yet implemented.
Usage
fit_bf(
x,
loss = "loss",
exposure = "premium",
prior,
bootstrap = NULL,
B = 999L,
seed = NULL,
type = c("parametric", "nonparametric", "analytical"),
residual = c("cell", "link"),
process = c("gamma", "od_pois", "normal"),
alpha = 1,
sigma_method = c("locf", "min_last2", "loglinear", "mack", "none"),
recent = NULL,
regime = NULL,
maturity = NULL,
credibility = NULL,
conf_level = 0.95,
...
)Arguments
- x
A
Triangleobject.- loss
A single cumulative loss variable to project. Default
"loss".- exposure
A single cumulative premium variable used as the denominator of the prior ELR. Default
"premium".- prior
The a priori expected loss ratio. Accepts:
- single numeric
Applied uniformly to every cohort.
- per-cohort
data.frame(cohort+elr) Per-cohort ELR. Must cover every cohort present in
x(extras are silently dropped, missing cohorts raise an error).- per-group
data.frame(grouping columns +elr) One ELR per group, broadcast to every cohort in that group. Useful when a single a priori ELR is set per line of business. Must cover every group present in
x.
A
data.frameprior may also carry an optionalelr_secolumn – the standard error of the a priori ELR (a distribution prior). When supplied, the bootstrap path draws a per-replicate ELR fromNormal(elr, elr_se)instead of treating the prior as a fixed point. Omit it (or leaveNA) for a deterministic prior.- bootstrap
Bootstrap configuration. Five forms accepted:
NULL/FALSE(default)Point estimate only – no bootstrap SE/CI.
TRUE/"auto"Internal
bootstrap()calls (one for loss, one for premium) sharingseedso replicate indices align across the two simulations.- Named list
list(loss = BootstrapTriangle, premium = BootstrapTriangle) Pre-built objects from
bootstrap(). Must have matchingmeta$B/meta$seedso per-replicate composition is well-defined;meta$targetmust be"loss"and"premium"respectively.- Function
function(tri) -> list(loss = ..., premium = ...) Lazy spec invoked on the input Triangle (leakage-safe for
backtest()).
Latest observed cumulative loss is not perturbed in the BF recipe – it is treated as the cohort anchor, mirroring the point-estimate formula.
- B
Integer number of bootstrap replicates. Used only when
bootstrapresolves to"auto". Default999.- seed
Optional integer seed for reproducible bootstrap. Default
NULL.- type
One of
"parametric"(default),"nonparametric", or"analytical"."parametric"/"nonparametric"select the bootstrap residual paradigm;"analytical"skips simulation and uses the closed-form Mack (2008) BF MSEP decomposition for the cohort-level SE / CI. When no bootstrap is requested the analytical path is used regardless oftype.- residual
Residual scope for
type = "nonparametric". One of"cell"(default) or"link". Seebootstrap().- process
One of
"gamma"(default),"od_pois", or"normal". Seebootstrap().- alpha
Numeric scalar passed through to the inner
fit_cl()andfit_premium()calls. Default1.- sigma_method
Sigma extrapolation method forwarded to
fit_cl()/fit_premium(). Default"locf".- recent
Optional positive integer; calendar-diagonal filter forwarded to the inner fits. Default
NULL.- regime
Optional regime specification forwarded to the inner loss and premium fits. See
fit_cl()for the four-type dispatch.- maturity
Optional maturity specification forwarded to the inner loss fit. See
fit_cl()for the four-type dispatch.- credibility
Optional credibility specification.
NULL(default) gives the classical BF blend with weight equal to the emergence fractionq. A listlist(method = "bs", K = NULL)switches to a Buehlmann-Straub credibility blendult = Z * CL + (1 - Z) * prior, whereZ = K / (K + s^2),s^2is the variance of the cohort's own CL loss-ratio estimate, andKis the variance of the hypothetical means (the genuine between-cohort spread).Kis estimated per group whenNULL, or supplied as a non-negative numeric scalar. The credibility weight protects rare-event cohorts: a green cohort with a CL estimate built on almost no data has a larges^2, soZshrinks toward 0 and the cohort is pulled to the prior even when itsqis high. A credibility blend always uses the analytical SE path (the SE is approximate – the credibility factor is treated as a fixed plug-in).- conf_level
Confidence level for the bootstrap quantile CI on
loss_ult. Default0.95.- ...
Reserved for future extension (currently unused).
Value
An object of class "BFFit" containing:
callThe matched call.
dataThe input
Triangle.method"bf".groupsGrouping variable names.
cohortRaw cohort variable name.
devRaw development variable name.
loss,premiumLoss / premium variable names.
fulldata.table[group, cohort, dev, loss_obs, loss_proj, premium_obs, premium_proj, is_observed, incr_loss_proj, incr_premium_proj]. Whenbootstrapis enabled, additional columnsloss_total_se,loss_total_cv,loss_ci_lo,loss_ci_hicarry per-cell bootstrap SE / CI on projected cells (observed cells stayNA).projSame shape as
full, with observed-cell projection columns NA'd out.summaryCohort-level reserve summary:
[group, cohort, latest, loss_ult, reserve, elr, q]. Whenbootstrapis enabled, additional columnsloss_total_se,loss_total_cv,loss_ci_lo,loss_ci_hicarry bootstrap SE / CI onloss_ult.priorResolved
data.table(group..., cohort, elr).qdata.table(group..., cohort, q)of expected emerged fractions.credibilityNULLfor the classical blend, or a listlist(method, weights)whereweightsis adata.table[group..., cohort, Z, K]of the Buehlmann-Straub credibility factors used in place ofq.cl_fitThe inner
CLFitused to derive \(q_i\).premium_fitThe inner
PremiumFitused to derive \(E_i^{ult}\).bootstrapWhen
bootstrapis enabled, aBFBootstraphelper holding both Triangle-levelBootstrapTriangleobjects and the per-replicate ultimate replicates;NULLotherwise.ci_type"bootstrap"when a bootstrap was run,"analytical"when the closed-form Mack (2008) MSEP was used. In the analytical case$summarycarriesloss_total_se,loss_total_cv,loss_ci_lo, andloss_ci_hi.alpha,sigma_method,recent,regime,maturityInputs forwarded to the inner
fit_cl()/fit_premium()calls.
References
Bornhuetter, R. L. and Ferguson, R. E. (1972). The actuary and IBNR. Proceedings of the Casualty Actuarial Society, 59, 181-195.
Mack, T. (2008). The prediction error of Bornhuetter/Ferguson. ASTIN Bulletin, 38(1), 87-103. (MSEP – not yet implemented.)
See also
fit_cc() (pooled ELR variant), fit_cl(),
fit_premium()
Examples
if (FALSE) { # \dontrun{
data(experience)
tri <- as_triangle(
experience[coverage == "surgery"],
groups = "coverage",
cohort = "uy_m",
calendar = "cy_m",
loss = "incr_loss",
premium = "incr_premium"
)
# Scalar prior: 0.7 ELR for every cohort
bf1 <- fit_bf(tri, prior = 0.7)
summary(bf1)
# Per-cohort prior table
prior_tbl <- data.frame(
cohort = unique(tri$cohort),
elr = c(0.6, 0.65, 0.7, 0.72, 0.75)
)
bf2 <- fit_bf(tri, prior = prior_tbl)
} # }
