Benktander#

class chainladder.Benktander(apriori=1.0, n_iters=1, apriori_sigma=0, random_state=None)[source]#

The Benktander (or iterated Bornhuetter-Ferguson) IBNR model

Parameters:
apriori: float, optional (default=1.0)

Multiplier for the sample_weight used in the Benktander method method. If sample_weight is already an apriori measure of ultimate, then use 1.0

n_iters: int, optional (default=1)

Number of iterations to use in the Benktander model. When n_iters=1, the result is equivalent to the BornhuetterFerguson method. When n_iters>>1, the result converges to the traditional Chainladder model.

apriori_sigma: float, optional (default=0.0)

Standard deviation of the apriori. When used in conjunction with the bootstrap model, the model samples aprioris from a lognormal distribution using this argument as a standard deviation.

random_state: int, RandomState instance or None, optional (default=None)

Seed for sampling from the apriori distribution. This is ignored when using as a deterministic method. If int, random_state is the seed used by the random number generator; If RandomState instance, random_state is the random number generator; If None, the random number generator is the RandomState instance used by np.random.

Attributes:
ultimate_: Triangle

The ultimate losses per the method

ibnr_: Triangle

The IBNR per the method

Examples

Benktander is the iterated Bornhuetter-Ferguson model. Like BF, it requires a per-origin apriori expected ultimate supplied through sample_weight. The n_iters parameter interpolates between BF (n_iters=1) and chainladder (n_iters large): each additional iteration shifts the ultimate further toward the chainladder estimate.

xyz = cl.load_sample("xyz")

ibnr = cl.Benktander().fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_
print(ibnr)
              2261
1998           NaN
1999    115.472127
2000    914.033812
2001   2432.394513
2002   6037.026677
2003  13928.934651
2004  33925.451475
2005  69724.761575
2006  73410.593920
2007  52977.560411
2008  45873.769490

When n_iters=1, the model is exactly the same as the BornhuetterFerguson model.

xyz = cl.load_sample("xyz")

bk_ibnr = (
    cl.Benktander(n_iters=1)
    .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal)
    .ibnr_
)
bf_ibnr = (
    cl.BornhuetterFerguson()
    .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal)
    .ibnr_
)
print(bk_ibnr - bf_ibnr)
      2261
1998   NaN
1999   NaN
2000   NaN
2001   NaN
2002   NaN
2003   NaN
2004   NaN
2005   NaN
2006   NaN
2007   NaN
2008   NaN

When n_iters>>1, the model converges to the traditional Chainladder model.

xyz = cl.load_sample("xyz")

bk_ibnr = cl.Benktander(n_iters=1000).fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal).ibnr_
cl_ibnr = cl.Chainladder().fit(xyz["Paid"]).ibnr_
print(bk_ibnr - cl_ibnr)
              2261
1998           NaN
1999           NaN
2000           NaN
2001  1.455192e-11
2002 -7.275958e-12
2003  7.275958e-12
2004  1.455192e-11
2005 -1.455192e-11
2006  2.910383e-11
2007 -5.820766e-11
2008 -7.275958e-11
fit(X, y=None, sample_weight=None)[source]#

Applies the Benktander technique to triangle X

Parameters:
X: Triangle

Loss data to which the model will be applied.

y: None

Ignored

sample_weight: Triangle

Required exposure to be used in the calculation.

Returns:
self: object

Returns the instance itself.

Examples

Fit returns the estimator itself, with ultimate_ populated. The repr shows non-default parameters.

xyz = cl.load_sample("xyz")

ultimate = (
    cl.Benktander(apriori=1, n_iters=2)
    .fit(X=xyz["Paid"], sample_weight=xyz["Premium"].latest_diagonal)
    .ultimate_
)
print(ultimate)
              2261
1998  15822.000000
1999  24908.397003
2000  37547.676656
2001  40511.198946
2002  49417.354765
2003  50042.095135
2004  82437.601111
2005  95417.171135
2006  88485.508416
2007  66882.788227
2008  50708.755370
predict(X, sample_weight=None)[source]#

Predicts the Benktander ultimate on a new triangle X

Parameters:
X: Triangle

Loss data to which the model will be applied.

sample_weight: Triangle

Required exposure to be used in the calculation.

Returns:
X_new: Triangle

Loss data with Benktander ultimate applied

Examples

Fit on a prior-period view of the data, then apply the model to the current Triangle and a refreshed apriori.

tr = cl.load_sample('ukmotor')
tr_prior = tr[tr.valuation < tr.valuation_date]
apriori_prior = cl.Chainladder().fit(tr_prior).ultimate_ * 0 + 14000
apriori = cl.Chainladder().fit(tr).ultimate_ * 0 + 14000
model = cl.Benktander(apriori=1.0, n_iters=2).fit(
    tr_prior, sample_weight=apriori_prior
)

print(model.predict(tr, sample_weight=apriori).ultimate_)
              2261
2007  12690.000000
2008  12746.000000
2009  13642.189922
2010  12740.812082
2011  13516.188545
2012  15914.716737
2013  17193.715555

Inherited Methods

Benktander.fit_predict

Benktander.get_metadata_routing

Get metadata routing of this object.

Benktander.get_params

Get parameters for this estimator.

Benktander.intersection

Given two Triangles with mismatched indices, this method aligns their indices

Benktander.pipe

Benktander.set_backend

Converts triangle array_backend.

Benktander.set_params

Set the parameters of this estimator.

Benktander.to_json

Serializes triangle object to json format

Benktander.to_pickle

Serializes triangle object to pickle.

Benktander.validate_X

Benktander.validate_weight