def test_voting_ultimate(): clrd = cl.load_sample("clrd")[["CumPaidLoss", "EarnedPremDIR"]] clrd = clrd[clrd["LOB"] == "wkcomp"] bcl_ult = cl.Chainladder().fit(clrd["CumPaidLoss"].sum(), ).ultimate_ bf_ult = cl.BornhuetterFerguson().fit( clrd["CumPaidLoss"].sum(), sample_weight=clrd["EarnedPremDIR"].sum().latest_diagonal).ultimate_ cc_ult = cl.CapeCod().fit( clrd["CumPaidLoss"].sum(), sample_weight=clrd["EarnedPremDIR"].sum().latest_diagonal).ultimate_ bcl = cl.Chainladder() bf = cl.BornhuetterFerguson() cc = cl.CapeCod() estimators = [('bcl', bcl), ('bf', bf), ('cc', cc)] weights = np.array([[0.25, 0.25, 0.5]] * 4 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3) vot_ult = cl.VotingChainladder(estimators=estimators, weights=weights).fit( clrd["CumPaidLoss"].sum(), sample_weight=clrd["EarnedPremDIR"].sum().latest_diagonal, ).ultimate_ weights = weights[..., np.newaxis] assert abs((bcl_ult * weights[..., 0, :] + bf_ult * weights[..., 1, :] + cc_ult * weights[..., 2, :]).sum() - vot_ult.sum()) < 1
def test_groupby(clrd): clrd = clrd[clrd['LOB'] == 'comauto'] # But only the top 10 get their own CapeCod aprioris. Smaller companies get grouped together top_10 = clrd['EarnedPremDIR'].groupby('GRNAME').sum().latest_diagonal top_10 = top_10.loc[..., '1997', :].to_frame().nlargest(10) cc_groupby = clrd.index['GRNAME'].map( lambda x: x if x in top_10.index else 'Remainder') idx = clrd.index idx['Top 10'] = cc_groupby clrd.index = idx # All companies share the same development factors regardless of size X = cl.Development().fit(clrd['CumPaidLoss'].sum()).transform( clrd['CumPaidLoss']) sample_weight = clrd['EarnedPremDIR'].latest_diagonal a = cl.CapeCod(groupby='Top 10', decay=0.98, trend=0.02).fit(X, sample_weight=sample_weight).ibnr_.groupby( 'Top 10').sum().sort_index() b = cl.CapeCod(decay=0.98, trend=0.02).fit(X.groupby('Top 10').sum(), sample_weight=sample_weight.groupby( 'Top 10').sum()).ibnr_.sort_index() xp = a.get_array_module() b = b.set_backend(a.array_backend) xp.allclose(xp.nan_to_num(a.values), xp.nan_to_num(b.values), atol=1e-5)
def test_trend1(): tri = cl.load_sample('clrd')[['CumPaidLoss', 'EarnedPremDIR']].sum() assert (cl.CapeCod(.05).fit( tri['CumPaidLoss'], sample_weight=tri['EarnedPremDIR'].latest_diagonal).ibnr_ == cl.CapeCod().fit( cl.Trend(.05).fit_transform(tri['CumPaidLoss']), sample_weight=tri['EarnedPremDIR'].latest_diagonal).ibnr_)
def test_weight_broadcasting(): clrd = cl.load_sample("clrd")[["CumPaidLoss", "EarnedPremDIR"]] clrd = clrd[clrd["LOB"] == "wkcomp"] bcl = cl.Chainladder() bf = cl.BornhuetterFerguson() cc = cl.CapeCod() estimators = [('bcl', bcl), ('bf', bf), ('cc', cc)] min_dim_weights = np.array([[1, 2, 3]] * 4 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3) mid_dim_weights = np.array( [[[1, 2, 3]] * 4 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3] * 1) max_dim_weights = np.array( [[[[1, 2, 3]] * 4 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3] * 1] * 132) min_dim_ult = cl.VotingChainladder( estimators=estimators, weights=min_dim_weights).fit( clrd['CumPaidLoss'], sample_weight=clrd["EarnedPremDIR"].latest_diagonal, ).ultimate_.sum() mid_dim_ult = cl.VotingChainladder( estimators=estimators, weights=mid_dim_weights).fit( clrd['CumPaidLoss'], sample_weight=clrd["EarnedPremDIR"].latest_diagonal, ).ultimate_.sum() max_dim_ult = cl.VotingChainladder( estimators=estimators, weights=max_dim_weights).fit( clrd['CumPaidLoss'], sample_weight=clrd["EarnedPremDIR"].latest_diagonal, ).ultimate_.sum() assert (abs(min_dim_ult - mid_dim_ult - max_dim_ult) < 1)
def test_voting_ultimate(triangle_data, estimators, weights): bcl_ult = cl.Chainladder().fit( triangle_data["CumPaidLoss"].sum(), ).ultimate_ bf_ult = cl.BornhuetterFerguson().fit( triangle_data["CumPaidLoss"].sum(), sample_weight=triangle_data["EarnedPremDIR"].sum( ).latest_diagonal).ultimate_ cc_ult = cl.CapeCod().fit(triangle_data["CumPaidLoss"].sum(), sample_weight=triangle_data["EarnedPremDIR"].sum( ).latest_diagonal).ultimate_ vot_ult = cl.VotingChainladder( estimators=estimators, weights=weights, default_weighting=(1, 2, 3)).fit( triangle_data["CumPaidLoss"].sum(), sample_weight=triangle_data["EarnedPremDIR"].sum().latest_diagonal, ).ultimate_ direct_weight = np.array([[1, 2, 3]] * 4 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3) direct_weight = direct_weight[..., np.newaxis] assert abs(( (bcl_ult * direct_weight[..., 0, :] + bf_ult * direct_weight[..., 1, :] + cc_ult * direct_weight[..., 2, :]) / direct_weight.sum(axis=-2)).sum() - vot_ult.sum()) < 1
def test_pipeline(): tri = cl.load_sample('clrd').groupby('LOB').sum()[[ 'CumPaidLoss', 'IncurLoss', 'EarnedPremDIR' ]] tri['CaseIncurredLoss'] = tri['IncurLoss'] - tri['CumPaidLoss'] X = tri[['CumPaidLoss', 'CaseIncurredLoss']] sample_weight = tri['EarnedPremDIR'].latest_diagonal dev = [ cl.Development(), cl.ClarkLDF(), cl.Trend(), cl.IncrementalAdditive(), cl.MunichAdjustment(paid_to_incurred=('CumPaidLoss', 'CaseIncurredLoss')), cl.CaseOutstanding(paid_to_incurred=('CumPaidLoss', 'CaseIncurredLoss')) ] tail = [cl.TailCurve(), cl.TailConstant(), cl.TailBondy(), cl.TailClark()] ibnr = [ cl.Chainladder(), cl.BornhuetterFerguson(), cl.Benktander(n_iters=2), cl.CapeCod() ] for model in list(itertools.product(dev, tail, ibnr)): print(model) cl.Pipeline( steps=[('dev', model[0]), ('tail', model[1]), ('ibnr', model[2])]).fit_predict( X, sample_weight=sample_weight).ibnr_.sum( 'origin').sum('columns').sum()
def estimators(): bcl = cl.Chainladder() bf = cl.BornhuetterFerguson() cc = cl.CapeCod() estimators = [('bcl', bcl), ('bf', bf), ('cc', cc)] return estimators
def test_struhuss(): X = cl.load_sample("cc_sample")["loss"] X = cl.TailConstant(tail=1 / 0.85).fit_transform( cl.Development().fit_transform(X)) sample_weight = cl.load_sample("cc_sample")["exposure"].latest_diagonal ibnr = int( cl.CapeCod(trend=0.07, decay=0.75).fit(X, sample_weight=sample_weight).ibnr_.sum()) assert ibnr == 17052
def test_misaligned_index2(clrd): clrd = clrd['CumPaidLoss'] w = cl.load_sample('clrd')['EarnedPremDIR'].latest_diagonal bcl = cl.Chainladder().fit( cl.Development(groupby=['LOB']).fit_transform(clrd)) bbk = cl.Benktander().fit( cl.Development(groupby=['LOB']).fit_transform(clrd), sample_weight=w) bcc = cl.CapeCod().fit(cl.Development(groupby=['LOB']).fit_transform(clrd), sample_weight=w) a = bcl.ultimate_.iloc[:10].sum().sum() b = bcl.predict(clrd.iloc[:10]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bbk.ultimate_.iloc[:10].sum().sum() b = bbk.predict(clrd.iloc[:10], sample_weight=w.iloc[:10]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcc.ultimate_.iloc[:10].sum().sum() b = bcc.predict(clrd.iloc[:10], sample_weight=w.iloc[:10]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcl.ultimate_.iloc[150:153].sum().sum() b = bcl.predict(clrd.iloc[150:153]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bbk.ultimate_.iloc[150:153].sum().sum() b = bbk.predict(clrd.iloc[150:153], sample_weight=w.iloc[150:153]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcc.ultimate_.iloc[150:153].sum().sum() b = bcc.predict(clrd.iloc[150:153], sample_weight=w.iloc[150:153]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcl.ultimate_.iloc[150:152].sum().sum() b = bcl.predict(clrd.iloc[150:152]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bbk.ultimate_.iloc[150:152].sum().sum() b = bbk.predict(clrd.iloc[150:152], sample_weight=w.iloc[150:152]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcc.ultimate_.iloc[150:152].sum().sum() b = bcc.predict(clrd.iloc[150:152], sample_weight=w.iloc[150:152]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcl.ultimate_.iloc[150].sum().sum() b = bcl.predict(clrd.iloc[150]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bbk.ultimate_.iloc[150].sum().sum() b = bbk.predict(clrd.iloc[150], sample_weight=w.iloc[150]).ultimate_.sum().sum() assert abs(a - b) < 1e-5 a = bcc.ultimate_.iloc[150].sum().sum() b = bcc.predict(clrd.iloc[150], sample_weight=w.iloc[150]).ultimate_.sum().sum() assert abs(a - b) < 1e-5
def test_voting_predict(): bcl = cl.Chainladder() bf = cl.BornhuetterFerguson() cc = cl.CapeCod() estimators = [('bcl', bcl), ('bf', bf), ('cc', cc)] weights = np.array([[1, 2, 3]] * 3 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3) vot = cl.VotingChainladder(estimators=estimators, weights=weights).fit( raa_1989, sample_weight=apriori_1989, ) vot.predict(raa_1990, sample_weight=apriori_1990)
def test_different_backends(): clrd = cl.load_sample("clrd")[["CumPaidLoss", "EarnedPremDIR"]] clrd = clrd[clrd["LOB"] == "wkcomp"] bcl = cl.Chainladder() bf = cl.BornhuetterFerguson() cc = cl.CapeCod() estimators = [('bcl', bcl), ('bf', bf), ('cc', cc)] weights = np.array([[1, 2, 3]] * 4 + [[0, 0.5, 0.5]] * 3 + [[0, 0, 1]] * 3) model = cl.VotingChainladder(estimators=estimators, weights=weights).fit( clrd["CumPaidLoss"].sum().set_backend("numpy"), sample_weight=clrd["EarnedPremDIR"].sum().latest_diagonal.set_backend( "numpy"), ) assert (abs( (model.predict(clrd["CumPaidLoss"].sum().set_backend("sparse"), sample_weight=clrd["EarnedPremDIR"].sum(). latest_diagonal.set_backend("sparse")).ultimate_.sum() - model.ultimate_.sum())) < 1)
# Loss on-leveling factors tort_reform = pd.DataFrame({ 'date': ['1/1/2006', '1/1/2007'], 'rate_change': [-0.1067, -.25] }) # In addition to development, include onlevel estimator in pipeline for loss pipe = cl.Pipeline(steps=[('olf', cl.ParallelogramOLF(tort_reform, change_col='rate_change', date_col='date', vertical_line=True) ), ('dev', cl.Development( n_periods=2)), ('model', cl.CapeCod(trend=0.034))]) # Define X X = cl.load_sample('xyz')['Incurred'] # Separately apply on-level factors for premium sample_weight = cl.ParallelogramOLF(rate_history, change_col='rate_change', date_col='date', vertical_line=True).fit_transform( xyz['Premium'].latest_diagonal) # Fit Cod Estimator pipe.fit(X, sample_weight=sample_weight).named_steps.model.ultimate_ # Create a Cape Cod pipeline without onleveling
def get_apriori(decay, trend): """ Function to grab apriori array from cape cod method """ cc = cl.CapeCod(decay=decay, trend=trend) cc.fit(ppauto_loss, sample_weight=ppauto_prem) return cc.detrended_apriori_.to_frame()
def test_cc_predict(): cc = cl.CapeCod().fit(raa_1989, sample_weight=apriori_1989) cc.predict(raa, sample_weight=apriori)
========================== This example demonstrates how you can can use the Voting Chainladder method. """ import numpy as np import pandas as pd import chainladder as cl # Load the data raa = cl.load_sample('raa') cl_ult = cl.Chainladder().fit(raa).ultimate_ # Chainladder Ultimate apriori = cl_ult * 0 + (float(cl_ult.sum()) / 10) # Mean Chainladder Ultimate # Load estimators to vote between bcl = cl.Chainladder() cc = cl.CapeCod() estimators = [('bcl', bcl), ('cc', cc)] # Fit VotingChainladder using CC after 1987 and a blend of BCL and CC otherwise vot = cl.VotingChainladder( estimators=estimators, weights=lambda origin: (0, 1) if origin.year > 1987 else (0.5, 0.5) ) vot.fit(raa, sample_weight=apriori) # Plotting bcl_ibnr = bcl.fit(raa).ibnr_.to_frame() cc_ibnr = cc.fit(raa, sample_weight=apriori).ibnr_.to_frame() vot_ibnr = vot.ibnr_.to_frame() plot_ibnr = pd.concat([bcl_ibnr, vot_ibnr, cc_ibnr], axis=1)