Package: trikit
trikit Quickstart GuideAuthor:James D. TriveriRelease:0.3.6trikit is a collection of Loss Reserving utilities developed to
facilitate Actuarial analysis in Python, with particular emphasis on
automating the basic techniques generally used for estimating unpaid
claim liabilities. trikit's core data structure is the triangle, which
comes in both incremental and cumulative varieties. trikit's triangle
objects inherit directly from Pandas DataFrame, so all of the familiar
methods and attributes used when working in Pandas can be be applied
to trikit triangle objects.Along with the coreIncrTriangleandCumTriangledata structures,
trikit exposes a number of common methods for estimating unpaid claim
liabilities, as well as techniques to quantify variability around those
estimates. Currently available reserve estimators areBaseChainLadder,MackChainLadderandBootstrapChainLadder. Refer to the examples
below for sample use cases.Finally, in addition to the library's core Chain Ladder functionality,
trikit exposes a convenient interface that links to the Casualty
Actuarial Society's Schedule P Loss Rerserving Database. The database
contains information on Commercial Auto losses for all property-casualty
insurers that write business in the U.S. More information related to the
the Schedule P Loss Reserving Database can be foundhere.Documentation:trikit documentation is availablehere.Installationtrikit can be installed by running:$python-mpipinstalltrikitQuickstartWe begin by loading the RAA sample dataset, which represents Automatic
Factultative business in General Liability provided by the Reinsurance
Association of America. Sample datasets are loaded as DataFrame objects,
and always represent incremental losses. Sample datasets can be loaded
as follows:In[1]:importtrikitIn[2]:raa=trikit.load("raa")In[3]:raa.head()Out[3]:origindevvalue0198115012119812325721981326383198148984198151734A list of available datasets can be obtained by callingget_datasets:In[4]:trikit.get_datasets()Out[4]:['amw09','autoliab','glre','raa','singinjury','singproperty','ta83']Any of the datasets listed above can be read in the same way usingtrikit.load. Note that sample datasets can be returned as triangle objects directly. For
example, the RAA dataset can be returned as a cumulative triangle as follows:In[5]:tri=trikit.load("raa",tri_type="cum")In[6]:triOut[6]:1234567891019815,0128,26910,90711,80513,53916,18118,00918,60818,66218,83419821064,2855,39610,66613,78215,59915,49616,16916,704nan19833,4108,99213,87316,14118,73522,21422,86323,466nannan19845,65511,55515,76621,26623,42526,08327,067nannannan19851,0929,56515,83622,16925,95526,180nannannannan19861,5136,44511,70212,93515,852nannannannannan19875574,02010,94612,314nannannannannannan19881,3516,94713,112nannannannannannannan19893,1335,395nannannannannannannannan19902,063nannannannannannannannannanWorking with TrianglesTriangles are created by calling thetotrifunction. Available
arguments are:data: The dataset to transform into a triangle instance.tri_type: {"cum", "incr"} Specifies the type of triangle to
create.data_format: {"cum", "incr"} Specifies how losses are
represented with the input datasetdata.data_shape: {"tabular", "triangle"} Specifies whether input
datasetdatarepresents tabular loss data with columns "origin",
"dev" and "value", or data already structured as a loss triangle
with columns corresponding to development periods.origin: The column name indatacorresponding to accident year.
Ignored ifdata_shape="triangle".dev: The column name indatacorresponding to development
period. Ignored ifdata_shape="triangle".value: The column name indatacorresponding to the measure of
interest. Ignored ifdata_shape="triangle".Next we demonstrate how to create triangles usingtotriand various
combinations of the arguments listed above.Example 1:Create a cumulative loss triangle from tabular incremental dataReferring again to the RAA dataset, let's create a cumulative loss
triangle. We mentioned above that trikit sample datasets are Pandas
DataFrames which reflect incremental losses, sodata_format="incr"anddata_shape="tabular", both of which are defaults. Also, the default
fortri_typeis"cum", so the only argument required to pass intototriis the input datasetdata:In[1]:importpandasaspdIn[2]:fromtrikitimportload,totriIn[3]:raa=load("raa")In[4]:tri=totri(raa)In[5]:triOut[5]:1234567891019815,0128,26910,90711,80513,53916,18118,00918,60818,66218,83419821064,2855,39610,66613,78215,59915,49616,16916,704nan19833,4108,99213,87316,14118,73522,21422,86323,466nannan19845,65511,55515,76621,26623,42526,08327,067nannannan19851,0929,56515,83622,16925,95526,180nannannannan19861,5136,44511,70212,93515,852nannannannannan19875574,02010,94612,314nannannannannannan19881,3516,94713,112nannannannannannannan19893,1335,395nannannannannannannannan19902,063nannannannannannannannannantriis an instance oftrikit.triangle.CumTriangle, which inherits from pandas.DataFrame:In[6]:type(tri)Out[6]:trikit.triangle.CumTriangleIn[7]:isinstance(tri,pd.DataFrame)Out[7]:TrueThis means that all of the functionality exposed by DataFrame objects
gets inherited by triangle objects. For example, to access the first
column oftri:In[8]:tri.loc[:,1]Out[8]:19815012.000001982106.0000019833410.0000019845655.0000019851092.0000019861513.000001987557.0000019881351.0000019893133.0000019902063.00000Name:1,dtype:float64Triangle objects offer a number of methods useful in Actuarial reserving
contexts. To extract the latest diagonal, calltri.latest:In[9]:tri.latestOut[9]:origindevlatest019811018834.0000011982916704.0000021983823466.0000031984727067.0000041985626180.0000051986515852.0000061987412314.0000071988313112.000008198925395.000009199012063.00000Callingtri.a2aproduces a DataFrame of age-to-age factors:In[10]:tri.a2aOut[10]:12345678919811.649841.319021.082331.146891.195141.112971.033261.002901.00922198240.424531.259281.976651.292141.131840.993401.043431.03309nan19832.636951.542821.163481.160711.185701.029221.02637nannan19842.043321.364431.348851.101521.113471.03773nannannan19858.759161.655621.399911.170781.00867nannannannan19864.259751.815671.105371.22551nannannannannan19877.217242.722891.12498nannannannannannan19885.142121.88743nannannannannannannan19891.72199nannannannannannannannanCallingtri.a2a_avgsproduces a table of candidate loss development
factors, which contains arithmetic, geometric and weighted age-to-age
averages for a number of different periods:In[11]:tri.a2a_avgs()Out[11]:123456789simple-11.721991.887431.124981.225511.008671.037731.026371.033091.00922simple-23.432052.305161.115171.198151.061071.033471.034901.017991.00922simple-34.693782.142001.210091.165941.102611.020111.034361.017991.00922simple-44.585272.020401.244781.164631.109921.043331.034361.017991.00922simple-55.420051.889211.228521.190131.126961.043331.034361.017991.00922simple-64.857261.831481.353211.182931.126961.043331.034361.017991.00922simple-74.540071.749731.314511.182931.126961.043331.034361.017991.00922simple-89.025631.695891.314511.182931.126961.043331.034361.017991.00922all-simple8.206101.695891.314511.182931.126961.043331.034361.017991.00922geometric-11.721991.887431.124981.225511.008671.037731.026371.033091.00922geometric-22.975682.266991.115131.197831.059771.033461.034871.017881.00922geometric-33.998052.105291.202961.164831.100191.019931.034331.017881.00922geometric-44.061931.982551.237881.163801.108021.042441.034331.017881.00922geometric-54.736721.839801.222631.188401.124921.042441.034331.017881.00922geometric-64.117381.786601.324551.181381.124921.042441.034331.017881.00922geometric-73.863451.699521.286881.181381.124921.042441.034331.017881.00922geometric-85.181251.646521.286881.181381.124921.042441.034331.017881.00922all-geometric4.562611.646521.286881.181381.124921.042441.034331.017881.00922weighted-11.721991.887431.124981.225511.008671.037731.026371.033091.00922weighted-22.752452.193671.114841.190951.058381.033811.033261.016941.00922weighted-33.245782.053761.232151.157211.093401.023951.033261.016941.00922weighted-43.479861.912591.266061.157991.099871.041931.033261.016941.00922weighted-54.233851.748211.245171.175191.113381.041931.033261.016941.00922weighted-63.302531.709351.298861.171671.113381.041931.033261.016941.00922weighted-73.166721.672121.270891.171671.113381.041931.033261.016941.00922weighted-83.401561.623521.270891.171671.113381.041931.033261.016941.00922all-weighted2.999361.623521.270891.171671.113381.041931.033261.016941.00922We can obtain a reference to an incremental representation of the
cumulative triangle by callingtri.to_incr:In[12]:tri.to_incr()Out[12]:1234567891019815,0123,2572,6388981,7342,6421,8285995417219821064,1791,1115,2703,1161,817-103673535nan19833,4105,5824,8812,2682,5943,479649603nannan19845,6555,9004,2115,5002,1592,658984nannannan19851,0928,4736,2716,3333,786225nannannannan19861,5134,9325,2571,2332,917nannannannannan19875573,4636,9261,368nannannannannannan19881,3515,5966,165nannannannannannannan19893,1332,262nannannannannannannannan19902,063nannannannannannannannannanExample 2:Create an incremental loss triangle from tabular incremental dataThe call tototriis identical to Example #1, but we changetri_typefrom "cum" to "incr":In[1]:importpandasaspdIn[2]:fromtrikitimportload,totriIn[3]:raa=load("raa")In[4]:tri=totri(raa,tri_type="incr")In[5]:type(tri)Out[5]:trikit.triangle.IncrTriangleIn[6]:triOut[6]:1234567891019815,0123,2572,6388981,7342,6421,8285995417219821064,1791,1115,2703,1161,817-103673535nan19833,4105,5824,8812,2682,5943,479649603nannan19845,6555,9004,2115,5002,1592,658984nannannan19851,0928,4736,2716,3333,786225nannannannan19861,5134,9325,2571,2332,917nannannannannan19875573,4636,9261,368nannannannannannan19881,3515,5966,165nannannannannannannan19893,1332,262nannannannannannannannan19902,063nannannannannannannannannantrinow represents RAA losses in incremental format.It is possible to obtain a cumulative representation of an incremental
triangle object by callingtri.to_cum:In[7]:tri.to_cum()Out[7]:1234567891019815,0128,26910,90711,80513,53916,18118,00918,60818,66218,83419821064,2855,39610,66613,78215,59915,49616,16916,704nan19833,4108,99213,87316,14118,73522,21422,86323,466nannan19845,65511,55515,76621,26623,42526,08327,067nannannan19851,0929,56515,83622,16925,95526,180nannannannan19861,5136,44511,70212,93515,852nannannannannan19875574,02010,94612,314nannannannannannan19881,3516,94713,112nannannannannannannan19893,1335,395nannannannannannannannan19902,063nannannannannannannannannanExample 3:Create a cumulative loss triangle from data formatted as a triangleThere may be situations in which data is already formatted as a
triangle, and we're interested in creating a triangle instance from
this data. In the next example, we create a DataFrame with the same
shape as a triangle, which we then pass intototriwithdata_shape="triangle"to obtain a cumulative triangle instance:In[1]:importpandasaspdIn[2]:fromtrikitimportload,totriIn[3]:dftri=pd.DataFrame({1:[1010,1207,1555,1313,1905],2:[767,1100,1203,900,np.NaN],3:[444,623,841,np.NaN,np.NaN],4:[239,556,np.NaN,np.NaN,np.NaN],5:[80,np.NaN,np.NaN,np.NaN,np.NaN],},index=list(range(1,6)))In[4]:dftriOut[4]:1234511010.767.444.239.80.21207.1100.623.556.nan31555.1203.841.nannan41313.900.nannannan51905.nannannannanIn[5]:tri=totri(dftri,data_shape="triangle")In[6]:type(tri)Out[6]:trikit.triangle.CumTriangletrikit cumulative triangle instances expose a plot method, which
generates a faceted plot by origin representing the progression of
cumulative losses to date by development period. The exhibit can be
obtained as follows:In[5]:tri.plot()Reserve Estimatorstrikit includes a number of reserve estimators. Let's refer to the CAS
Loss Reserving Dastabase (lrdb) included with trikit, focusing ongrcode=1767andlob="comauto"(grcodeuniquely identifies each
company in the database. To obtain a full list of grcodes and associated
companies, usetrikit.get_lrdb_specs; to obtain a list of
available lines of business (lobs), usetrikit.get_lrdb_lobs):In[1]:fromtrikitimportload_lrdb,totriIn[2]:df=load_lrdb(lob="comauto",grcode=1767)In[3]:tri=totri(df)In[4]:tri123456789101988110,231263,079431,216611,278797,428985,5701,174,9221,366,2291,558,0961,752,0961989121,678279,896456,640644,767837,7331,033,8371,233,0151,432,6701,633,619nan1990123,376298,615500,570714,683934,6711,157,9791,383,8201,610,193nannan1991117,457280,058463,396662,003865,4011,071,2711,278,228nannannan1992124,611291,399481,170682,203889,0291,101,390nannannannan1993137,902323,854533,211753,639980,180nannannannannan1994150,582345,110561,315792,392nannannannannannan1995150,511345,241560,278nannannannannannannan1996142,301326,584nannannannannannannannan1997143,970nannannannannannannannannanSimilar toload,load_lrdbalso accepts atri_typeargument, which returns the lrdb subset
as an incremental or cumulative triangle:In[5]:tri=load_lrdb(tri_type="cum",lob="comauto",grcode=1767)To obtain base chain ladder reserve estimates, call the cumulative
triangle'sbase_clmethod:In[5]:result=tri.base_cl()In[6]:resultOut[6]:maturitycldfemergencelatestultimatereserve1988101.000001.000001,752,0961,752,0960198991.124510.889281,633,6191,837,022203,403199081.282330.779831,610,1932,064,802454,609199171.491110.670641,278,2281,905,977627,749199261.779360.562001,101,3901,959,771858,381199352.201460.45425980,1802,157,8221,177,642199442.870170.34841792,3922,274,2991,481,907199534.070520.24567560,2782,280,6241,720,346199626.687570.14953326,5842,184,0531,857,4691997115.625060.06400143,9702,249,5412,105,571totalnannan10,178,93020,666,00710,487,077The result is of typeBaseChainLadderResult. The columns ofresultcan be
accessed in total or individually. The result above can be returned as a DataFrame by callingresult.summary:In[7]:result.summaryOut[7]:maturitycldfemergencelatestultimatereserve1988101.0000001.0000001752096.01.752096e+060.000000e+00198991.1245110.8892751633619.01.837022e+062.034034e+05199081.2823320.7798291610193.02.064802e+064.546094e+05199171.4911080.6706421278228.01.905977e+066.277486e+05199261.7793620.5619991101390.01.959771e+068.583811e+05199352.2014550.454245980180.02.157822e+061.177642e+06199442.8701690.348412792392.02.274299e+061.481907e+06199534.0705230.245669560278.02.280624e+061.720346e+06199626.6875680.149531326584.02.184053e+061.857469e+061997115.6250640.064000143970.02.249541e+062.105571e+06totalNaNNaN10178930.02.066601e+071.048708e+07To access the reserve estimates as a Series, callresult.reserve:In[8]:result.reserveOut[8]:19880.01989203403.01990454609.01991627749.01992858381.019931177642.019941481907.019951720346.019961857469.019972105571.0total10487077.0Name:reserve,dtype:float64base_claccepts two optional arguments:tail: The tail factor, which defaults to 1.0.sel: Loss development factors, which defaults to "all-weighted".selcan be either a string corresponding to a pre-computed
pattern available intri.a2a_avgs().index, or a custom set of loss development factors as a numpy array or Pandas Series.Example #2 demonstrated how to access a number of candidate loss
development patterns by callingtri.a2a_avgs. Available pre-computed
options forselcan be any value present intri.a2a_avgs's index.
To obtain a list of available pre-computed loss development factors by
name, run:In[9]:tri.a2a_avgs().index.tolist()Out[9]:['simple-1','simple-2','simple-3','simple-4','simple-5','simple-6','simple-7','simple-8','all-simple','geometric-1','geometric-2','geometric-3','geometric-4','geometric-5','geometric-6','geometric-7','geometric-8','all-geometric','weighted-1','weighted-2','weighted-3','weighted-4','weighted-5','weighted-6','weighted-7','weighted-8','all-weighted']If instead ofall-weighted, a 5-year geometric loss development
pattern is preferred, along with a tail factor of 1.015, the call tobase_clwould be modified as follows:In[10]:tri.base_cl(sel="geometric-5",tail=1.015)Out[10]:maturitycldfemergencelatestultimatereserve1988101.015000.985221,752,0961,778,37726,281198991.141380.876131,633,6191,864,578230,959199081.301570.768301,610,1932,095,778485,585199171.513440.660751,278,2281,934,517656,289199261.805910.553741,101,3901,989,009887,619199352.234160.44760980,1802,189,8781,209,698199442.912490.34335792,3922,307,8321,515,440199534.135210.24183560,2782,316,8691,756,591199626.782920.14743326,5842,215,1941,888,6101997115.691490.06373143,9702,259,1032,115,133totalnannan10,178,93020,951,13510,772,205Ifselis a Series or numpy ndarray, a check will first be made to
ensure the LDFs have the requiste number of elements. The provided LDFs
should not include a tail factor.Next, reserves are estimated with the chain ladder method along with an
external set of LDFs using the same loss reserve database subset
(grcode=1767andlob="commauto"):In[11]:tri=load_lrdb(tri_type="cum",lob="commauto",grcode=1767)In[12]:ldfs=np.asarray([2.75,1.55,1.50,1.25,1.15,1.075,1.03,1.02,1.01])In[13]:cl=tri.base_cl(sel=ldfs)In[14]:clOut[14]:maturitycldfemergencelatestultimatereserve1988101.000001.000001,752,0961,752,0960198991.010000.990101,633,6191,649,95516,336199081.030200.970691,610,1931,658,82148,628199171.061110.942411,278,2281,356,33578,107199261.140690.876661,101,3901,256,343154,953199351.311790.76232980,1801,285,793305,613199441.639740.60985792,3921,299,317506,925199532.459610.40657560,2781,378,066817,788199623.812400.26230326,5841,245,068918,4841997110.484090.09538143,9701,509,3941,365,424totalnannan10,178,93014,391,1884,212,258Ifldfsis not of the correct length (length n-1 for a triangle having n
development periods),ValueErroris raised:In[15]:ldfs=np.asarray([2.75,1.55,1.50,1.25,1.15,1.075,1.03])In[16]:result=tri.base_cl(sel=ldfs)Traceback(mostrecentcalllast):File"trikit\chainladder\base.py",line117,in__call__ValueError:selhas7values,LDFoverridesrequire9.A faceted plot by origin combining actuals and forcasts can be obtained
by callingresult's plot method:In[17]:result=tri.base_cl(sel="geometric-5",tail=1.015)In[18]:result.plot()Quantifying Reserve VariabilityThe Base Chain Ladder method provides an estimate by origin and in total
of future outstanding claim liabilities, but offers no indication of the
variability around those point estimates. We can obtain quantiles of the
predictive distribution of reserve estimates through a number of trikit
estimators.Mack Chain LadderThe Mack Chain Ladder is a distribution free model which estimates the
first two moments of standard chain ladder forecasts. Within trikit, the
Mack Chain Ladder method is dispatched by calling a cumulative triangle'smack_clmethod.mack_claccepts a number of optional arguments:alpha: Controls how loss development factors are computed. Can be
0, 1 or 2. Whenalpha=0, LDFs are computed as the straight average
of observed individual link ratios. Whenalpha=1, the historical
Chain Ladder age-to-age factors are computed. Whenalpha=2, a
regression of $C{k+1}$ on $C{k}$ with 0 intercept is
performed. Default is 1.dist: Either "norm" or "lognorm". Represents the selected
distribution to approximate the true distribution of reserves by
origin period and in aggregate. Settingdist="norm"specifies a
normal distribution.dist="lognorm"assumes a log-normal
distribution. Default is "lognorm".q: Quantile or sequence of quantiles to compute, which must be
between 0 and 1 inclusive. Default is [.75, .95].two_sided: Whether the two_sided interval should be included in
summary output. For example, iftwo_sided==Trueandq=.95, then
the 2.5th and 97.5th quantiles of the estimated reserve distribution
will be returned ((1 - .95) / 2, (1 + .95) / 2). When False, only
the specified quantile(s) will be computed. Default value is False.Using theta83sample dataset, callingmack_clwith default
arguments yields:In[1]:fromtrikitimportload,totriIn[2]:tri=load("ta83",tri_type="cum")In[3]:mcl=tri.mack_cl()In[4]:mclOut[4]:maturitycldfemergencelatestultimatereservestd_errorcv75%95%1101.000001.000003,901,4633,901,46300nannannan291.017720.982585,339,0855,433,71994,63475,5350.79818118,760234,717381.095640.912714,909,3155,378,826469,511121,7000.25921539,788691,334471.154660.866054,588,2685,297,906709,638133,5510.18820790,911947,870561.254280.797273,873,3114,858,200984,889261,4120.265421,135,1001,462,149651.384500.722283,691,7125,111,1711,419,459411,0280.289571,651,0452,174,408741.625200.615313,483,1305,660,7712,177,641558,3560.256402,500,7793,194,587832.368580.422192,864,4986,784,7993,920,301875,4300.223314,439,8775,499,652924.138700.241621,363,2945,642,2664,278,972971,3850.227014,853,9186,033,39910114.446620.06922344,0144,969,8384,625,8241,363,3760.294735,390,6897,133,025totalnannan34,358,09053,038,95918,680,8692,447,3180.1310120,226,19222,955,604Quantiles of the estimated reserve distribution can be obtained by callingget_quantiles.qcan be either a single float or an array of floats representing the percentiles of
interest (which must fall within [0, 1]):In[5]:mcl.get_quantiles(q=[.05,.10,.25,.50,.75,.90,.95])Out[5]:5th10th25th50th75th90th95th1nannannannannannannan223306.030078.046063.073962.0118760.0181873.0234717.03298788.0327792.0382673.0454491.0539788.0630163.0691334.04513108.0549091.0614936.0697395.0790911.0885754.0947870.05619750.0681372.0798314.0951928.01135100.01329915.01462149.06854941.0947780.01125948.01363448.01651045.01961416.02174408.071392853.01526576.01779281.02109405.02500779.02914751.03194587.082661766.02883868.03297115.03826066.04439877.05076093.05499652.092885978.03130850.03587259.04172800.04853918.05561511.06033399.0102760122.03065251.03652226.04437118.05390689.06422971.07133025.0total14945656.015671023.016962489.018522596.020226192.021893054.022955604.0TheMackChainLadderResult'splotmethod returns a faceted plot of estimated reserve
distributions by origin and in total. The mean is highlighted, along with any quantiles
passed to theplotmethod viaq. We can compare the estimated distributions whendist="lognorm"vs.dist="norm", highlighting the mean and 95th percentile. First we
take a look atdist="lognorm":In[7]:mcl.plot()Testing for Development Period CorrelationIn [1] Appendix G., Mack proposes an approximate test to assess whether
one of the basic Chain Ladder assumptions holds, namely that subsequent
development periods are uncorrelated. The test can be performed viaMackChainLadderResult'sdevp_corr_testmethod. We next apply the
test to the RAA dataset:In[1]:fromtrikitimportload,totriIn[2]:df=load("raa")In[3]:tri=totri(data=df)In[4]:mcl=tri.mack_cl()In[5]:mcl.devp_corr_test()Out[5]:((-0.12746658149149367,0.12746658149149367),0.0695578231292517)devp_corr_testreturns a 2-tuple: The first element represents the
bounds of the test interval ((-0.127, 0.127)). The second element is the
test statistic for the triangle under consideration. In this example,
the test statistic falls within the bounds of the test interval,
therefore we do not reject the null-hypothesis of having uncorrelated
development factors. If the test statistic falls outside the interval,
the correlations should be analyzed in more detail. Refer to [1] for
more information.Testing for Calendar Year EffectsIn [1] Appendix H., Mack proposes a test to assess the independence of
the origin periods. This test can be performed viaMackChainLadderResult'scy_effects_testmethod. Again using the RAA
dataset:In[1]:fromtrikitimportload,totriIn[2]:tri=load("raa",tri_type="cum")In[3]:mcl=tri.mack_cl()In[4]:mcl.cy_effects_test()Out[4]:((8.965613354894957,16.78438664510504),14.0)Similar todevp_corr_test,cy_effects_testreturns a 2-tuple, with
the first element representing the bounds of the test interval ((8.97,
16.78)) and the second element the test statistic. In this example, the
test statistic falls within the bounds of thew test interval, therefore
we do not reject the null-hypothesis of not having significant calendar
year influences. Refer to [1] for more information.Mack Chain Ladder DiagnosticsMackChainLadderResultexposes adiagnosticsmethod, which generates
a faceted plot that includes the estimated aggregate reserve
distribution, development by origin and standardized residuals by
development period and by origin:In[1]:fromtrikitimportload,totriIn[2]:tri=load("raa",tri_type="cum")In[3]:mcl=tri.mack_cl()In[4]:mcl.diagnostics()Bootstrap Chain LadderThe purpose of the Bootstrap Chain Ladder is to estimate the predicition
error of the total reserve estimate and to approximate the predictive
distribution. Within trikit, the Bootstrap Chain Ladder is encapsulated
within a cumulative triangle'sboot_clmethod.boot_claccepts a
number of optional arguments:sims: The number of bootstrap iterations to perform. Default value
is 1000.q: Quantile or sequence of quantiles to compute, which must be
between 0 and 1 inclusive. Default value is [.75, .95].procdist: The distribution used to incorporate process variance.
Currently, this can only be set to "gamma". This may change in a
future release.two_sided: Whether the two_sided prediction interval should be
included in summary output. For example, iftwo_sided=Trueandq=.95, then the 2.5th and 97.5th quantiles of the predictive
reserve distribution will be returned [(1 - .95) / 2, (1 + .95) /
2]. When False, only the specified quantile(s) will be included in
summary output. Default value is False.parametric: If True, fit standardized residuals to a normal
distribution via maximum likelihood, and sample from the
parameterized distribution. Otherwise, sample with replacement from
the collection of standardized fitted triangle residuals. Default
value is False.interpolation: One of {'linear', 'lower', 'higher', 'midpoint', 'nearest'}.
Default value is 'linear'. Refer tonumpy.quantilefor more information.random_state: If int, random_state is the seed used by the random
number generator; IfRandomStateinstance, random_state is the
random number generator; If None, the random number generator is theRandomStateinstance used by np.random. Default value is None.We next demonstrate how to apply the Bootstrap Chain Ladder to the RAA
dataset. The example setssims=1000,two_sided=Falseandrandom_state=516for reproducibility:In[1]:fromtrikitimportload,totriIn[2]:tri=load("raa",tri_type="cum")In[3]:bcl=tri.boot_cl(sims=1000,two_sided=False,random_state=516)In[4]:bclOut[4]:maturitycldfemergencelatestultimatereservestd_errorcv75%95%1981101.000001.0000018,83418,83400nan00198291.009220.9908716,70416,8631595293.3312451,108198381.026310.9743723,46624,3959291,0261.1041,1012,609198471.060450.9430027,06728,6481,5811,5921.0072,4724,704198561.104920.9050526,18029,0872,9071,8830.6483,9146,341198651.230200.8128815,85219,7623,9101,9310.4944,8927,114198741.441390.6937712,31417,7385,4242,5380.4686,94710,061198831.831850.5459013,11224,36511,2533,9800.35413,56518,735198922.974050.336245,39516,32510,9304,9400.45213,87019,879199018.920230.112102,06318,97316,91011,0280.65222,86337,008totalnannan160,987214,98954,00214,8320.27562,59780,200reserverepresents the mean of the predicitive distribution of reserve estimates
by origin and in total, and75%and95%represent quantiles of the distribution.Additional quantiles of the bootstrapped reserve distribution can be obtained by callingget_quantiles.qcan be either a single float or an array of floats representing the
percentiles of interest (which must fall within [0, 1]). We setlb=0to set negative
quantiles to 0:In[5]:bcl.get_quantiles(q=[.05,.10,.25,.75,.90,.95],lb=0)Out[5]:5th10th25th75th90th95th19810.00.00.00.00.00.019820.00.00.0245.0694.01108.019830.00.030.01101.02001.02609.019840.0142.0618.02472.03758.04704.01985349.0693.01449.03914.05234.06341.019861117.01454.02319.04892.06348.07114.019871838.02396.03555.06947.08832.010061.019885469.06452.08256.013565.016339.018735.019893671.04892.07257.013870.017667.019879.019901793.04278.08790.022863.030904.037008.0total31588.036193.043009.062597.073218.080200.0BoostrapChainLadderResultexposes two exhibits: The first is similar toBaseChainLadderResult'splot, but includes the upper and lower bounds of the specified quantile of the
predictive distribution. To obtain the faceted plot displaying the 5th and 95th
percentiles, run:In[5]:bcl=tri.boot_cl(sims=2500,two_sided=True,random_state=516)In[6]:bcl.plot(q=.90)In addition, we can obtain a faceted plot of the distribution of bootstrap samples by origin
and in aggregate by callingBoostrapChainLadderResult'shistmethod:In[7]:bcl.hist()There are a number of parameters which can be used to control the style of the
generated exhibits. Refer to the documentation for more information.ReferencesMack, Thomas (1993)Measuring the Variability of Chain Ladder
Reserve Estimates, 1993 CAS Prize Paper Competition on
Variability of Loss Reserves.Mack, Thomas, (1993),Distribution-Free Calculation of the Standard
Error of Chain Ladder Reserve Estimates, ASTIN Bulletin 23, no.
2:213-225.Mack, Thomas, (1999),The Standard Error of Chain Ladder Reserve
Estimates: Recursive Calculation and Inclusion of a Tail Factor,
ASTIN Bulletin 29, no. 2:361-366.England, P., and R. Verrall, (2002),Stochastic Claims Reserving in
General Insurance, British Actuarial Journal 8(3): 443-518.Murphy, Daniel, (2007),Chain Ladder Reserve Risk Estimators, CAS
E-Forum, Summer 2007.Carrato, A., McGuire, G. and Scarth, R. 2016.A Practitioner's
Introduction to Stochastic Reserving, The Institute and Faculty of
Actuaries. 2016.ContactPlease contactjames.triveri@gmail.comwith suggestions or feature
requests.Relevant Linkstrikit Source:https://github.com/trikit/trikitCAS Loss Reserving Database:https://www.casact.org/research/index.cfm?fa=loss_reserves_dataPython:https://www.python.org/Numpy:http://www.numpy.org/Scipy:https://docs.scipy.org/doc/scipy/reference/Pandas:https://pandas.pydata.org/Matplotlib:https://matplotlib.org/Seaborn:https://seaborn.pydata.org/