Skip to content

Commit

Permalink
docs and capecod hotfix
Browse files Browse the repository at this point in the history
  • Loading branch information
jbogaardt committed Jan 27, 2019
1 parent 72b5f62 commit d082de7
Show file tree
Hide file tree
Showing 123 changed files with 1,056 additions and 43 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ include chainladder/utils/data/raa.csv
include chainladder/utils/data/ukmotor.csv
include chainladder/utils/data/usaa.csv
include chainladder/utils/data/usauto.csv
include chainladder/utils/data/cc_sample.csv
2 changes: 1 addition & 1 deletion chainladder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
from chainladder.methods import *
from chainladder.workflow import *

__version__ = '0.2.3'
__version__ = '0.2.4'
19 changes: 18 additions & 1 deletion chainladder/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,24 @@ def cum_to_incr(self, inplace=False):

@check_triangle_postcondition
def grain(self, grain='', incremental=False, inplace=False):
''' TODO - Make incremental work '''
"""Changes the grain of a cumulative triangle.
Parameters
----------
grain : str
The grain to which you want your triangle converted, specified as
'O<x>D<y>' where <x> and <y> can take on values of `['Y', 'Q', 'M']`
For example, 'OYDY' for Origin Year/Development Year, 'OQDM' for
Origin quarter, etc.
incremental : bool
Not implemented yet
inplace : bool
Whether to mutate the existing Triangle instance or return a new one.
Returns
-------
Triangle
"""
if inplace:
origin_grain = grain[1:2]
development_grain = grain[-1]
Expand Down
59 changes: 32 additions & 27 deletions chainladder/methods/capecod.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,37 @@


class CapeCod(MethodBase):
"""Applies the CapeCod technique to triangle **X**
Parameters
----------
X : Triangle
The data used to compute the mean and standard deviation
used for later scaling along the features axis.
y : None
Ignored
sample_weight : Triangle
Required exposure to be used in the calculation.
Attributes
----------
triangle :
returns **X**
ultimate_ :
The ultimate losses per the method
ibnr_ :
The IBNR per the method
apriori_ :
The trended apriori vector developed by the Cape Cod Method
detrended_apriori_ :
The detrended apriori vector developed by the Cape Cod Method
"""

def __init__(self, trend=0, decay=1):
self.trend = trend
self.decay = decay

def fit(self, X, y=None, sample_weight=None):
"""Applies the CapeCod technique to triangle **X**
Parameters
----------
X : Triangle
The data used to compute the mean and standard deviation
used for later scaling along the features axis.
y : None
Ignored
sample_weight : Triangle
Required exposure to be used in the calculation.
Attributes
----------
triangle :
returns **X**
ultimate_ :
The ultimate losses per the method
ibnr_ :
The IBNR per the method
apriori_ :
The apriori vector developed by the Cape Cod Method
"""
super().fit(X, y, sample_weight)
self.sample_weight_ = sample_weight
latest = self.X_.latest_diagonal.triangle
Expand All @@ -49,19 +52,21 @@ def fit(self, X, y=None, sample_weight=None):
trend_exponent = exposure.shape[-2]-np.arange(exposure.shape[-2])-1
trend_array = (1+self.trend)**(trend_exponent)
trend_array = self.X_.expand_dims(np.expand_dims(trend_array, -1))
decay_matrix = self.decay * \
decay_matrix = self.decay ** \
(np.abs(np.expand_dims(np.arange(exposure.shape[-2]), 0).T -
np.expand_dims(np.arange(exposure.shape[-2]), 0)))
decay_matrix = self.X_.expand_dims(decay_matrix)
weighted_exposure = reported_exposure * decay_matrix
trended_ultimate = (latest*trend_array)/(reported_exposure)
weighted_exposure = np.swapaxes(reported_exposure, -1, -2)*decay_matrix
trended_ultimate = np.swapaxes((latest*trend_array) /
reported_exposure, -1, -2)
apriori = np.sum(weighted_exposure*trended_ultimate, -1) / \
np.sum(weighted_exposure, -1)

obj.triangle = np.expand_dims(apriori, -1)
obj.ddims = ['Apriori']
self.apriori_ = copy.deepcopy(obj)
detrended_ultimate = self.apriori_.triangle/trend_array
self.detrended_apriori_ = copy.deepcopy(obj)
self.detrended_apriori_.tiangle = detrended_ultimate
ibnr = detrended_ultimate*(1-1/cdf)*exposure
obj.triangle = latest + ibnr
obj.ddims = ['Ultimate']
Expand Down
8 changes: 8 additions & 0 deletions chainladder/methods/tests/test_capecod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import chainladder as cl

def test_struhuss():
X = cl.load_dataset('cc_sample')['loss']
X = cl.TailConstant(tail=1/0.85).fit_transform(cl.Development().fit_transform(X))
sample_weight = cl.load_dataset('cc_sample')['exposure'].latest_diagonal
ibnr = int(cl.CapeCod(trend=0.07, decay=0.75).fit(X, sample_weight=sample_weight).ibnr_.sum()[0])
assert ibnr == 17052
16 changes: 16 additions & 0 deletions chainladder/utils/data/cc_sample.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
,origin,development,loss,exposure
0,1993,1993,1058.823529,7000
1,1994,1994,1333.333333,8000
2,1995,1995,2000.0,9000
3,1996,1996,2000.0,10000
4,1997,1997,2800.0,11000
5,1993,1994,1905.8823530000002,7000
6,1994,1995,2400.0,8000
7,1995,1996,3600.0,9000
8,1996,1997,3600.0,10000
9,1993,1995,2541.176471,7000
10,1994,1996,3200.0,8000
11,1995,1997,4800.0,9000
12,1993,1996,3176.4705879999997,7000
13,1994,1997,4000.0,8000
14,1993,1997,3600.0,7000
4 changes: 3 additions & 1 deletion chainladder/utils/utility_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ def load_dataset(key):
development = 'DevelopmentYear'
index = ['GRNAME', 'LOB']
columns = ['IncurLoss', 'CumPaidLoss', 'BulkLoss', 'EarnedPremDIR',
'EarnedPremCeded', 'EarnedPremNet']
'EarnedPremCeded', 'EarnedPremNet']
if key.lower() in ['liab', 'auto']:
index = ['lob']
if key.lower() in ['cc_sample']:
columns = ['loss', 'exposure']
df = pd.read_csv(os.path.join(path, 'data', key.lower() + '.csv'))
return Triangle(df, origin=origin, development=development,
columns=columns, index=index)
Expand Down
4 changes: 2 additions & 2 deletions chainladder/workflow/gridsearch.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self, estimator, param_grid, scoring, verbose=0,
self.verbose = verbose
self.error_score = error_score

def fit(self, X):
def fit(self, X, y=None, sample_weight=None):
if type(self.scoring) is not dict:
scoring = dict(score=self.scoring)
else:
Expand All @@ -60,7 +60,7 @@ def fit(self, X):
results_ = []
for num, item in enumerate(grid):
est = copy.deepcopy(self.estimator).set_params(**item)
model = est.fit(X)
model = est.fit(X, y, sample_weight)
for score in scoring.keys():
item[score] = scoring[score](model)
results_.append(item)
Expand Down
Binary file modified docs/auto_examples/auto_examples_jupyter.zip
Binary file not shown.
Binary file modified docs/auto_examples/auto_examples_python.zip
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions docs/auto_examples/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ Gallery of Chainladder Functionality

/auto_examples/plot_bf_apriori_from_cl

.. raw:: html

<div class="sphx-glr-thumbcontainer" tooltip="This example demonstrates the relationship between the Chainladder and BornhuetterFerguson meth...">

.. only:: html

.. figure:: /auto_examples/images/thumb/sphx_glr_plot_benktander_thumb.png

:ref:`sphx_glr_auto_examples_plot_benktander.py`

.. raw:: html

</div>


.. toctree::
:hidden:

/auto_examples/plot_benktander

.. raw:: html

<div class="sphx-glr-thumbcontainer" tooltip="This example demonstrates the typical way you&#x27;d ingest data into a Triangle. Data in tabular fo...">
Expand Down Expand Up @@ -146,6 +166,26 @@ Gallery of Chainladder Functionality
:hidden:

/auto_examples/plot_munich

.. raw:: html

<div class="sphx-glr-thumbcontainer" tooltip="This example demonstrates the usage of the deterministic CapeCod method and shows the sensitivi...">

.. only:: html

.. figure:: /auto_examples/images/thumb/sphx_glr_plot_capecod_thumb.png

:ref:`sphx_glr_auto_examples_plot_capecod.py`

.. raw:: html

</div>


.. toctree::
:hidden:

/auto_examples/plot_capecod
.. raw:: html

<div style='clear:both'></div>
Expand Down
54 changes: 54 additions & 0 deletions docs/auto_examples/plot_benktander.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n====================================================================\nBenktander: Relationship between Chainladder and BornhuetterFerguson\n====================================================================\n\nThis example demonstrates the relationship between the Chainladder and\nBornhuetterFerguson methods by way fo the Benktander model. Each is a\nspecial case of the Benktander model where `n_iters = 1` for BornhuetterFerguson\nand as `n_iters` approaches infinity yields the chainladder. As `n_iters`\nincreases the apriori selection becomes less relevant regardless of initial\nchoice.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import chainladder as cl\n\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nsns.set_style('whitegrid')\n\n# Load Data\nclrd = cl.load_dataset('clrd')\nmedmal_paid = clrd.groupby('LOB').sum().loc['medmal']['CumPaidLoss']\nmedmal_prem = clrd.groupby('LOB').sum().loc['medmal']['EarnedPremDIR'].latest_diagonal\nmedmal_prem.rename(development='premium')\n\n# Generate LDFs and Tail Factor\nmedmal_paid = cl.Development().fit_transform(medmal_paid)\nmedmal_paid = cl.TailCurve().fit_transform(medmal_paid)\n\n# Benktander Model\nbenk = cl.Benktander()\n\n# Prep Benktander Grid Search with various assumptions, and a scoring function\nparam_grid = dict(n_iters=list(range(1,100,2)),\n apriori=[0.50, 0.75, 1.00])\nscoring = {'IBNR':lambda x: x.ibnr_.sum()[0]}\ngrid = cl.GridSearch(benk, param_grid, scoring=scoring)\n# Perform Grid Search\ngrid.fit(medmal_paid, sample_weight=medmal_prem)\n\n# Plot data\ngrid.results_.pivot(index='n_iters', columns='apriori', values='IBNR').plot()\nplt.title('Benktander convergence to Chainladder')\ng = plt.ylabel('IBNR')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
43 changes: 43 additions & 0 deletions docs/auto_examples/plot_benktander.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
====================================================================
Benktander: Relationship between Chainladder and BornhuetterFerguson
====================================================================
This example demonstrates the relationship between the Chainladder and
BornhuetterFerguson methods by way fo the Benktander model. Each is a
special case of the Benktander model where `n_iters = 1` for BornhuetterFerguson
and as `n_iters` approaches infinity yields the chainladder. As `n_iters`
increases the apriori selection becomes less relevant regardless of initial
choice.
"""
import chainladder as cl

import seaborn as sns
import matplotlib.pyplot as plt
sns.set_style('whitegrid')

# Load Data
clrd = cl.load_dataset('clrd')
medmal_paid = clrd.groupby('LOB').sum().loc['medmal']['CumPaidLoss']
medmal_prem = clrd.groupby('LOB').sum().loc['medmal']['EarnedPremDIR'].latest_diagonal
medmal_prem.rename(development='premium')

# Generate LDFs and Tail Factor
medmal_paid = cl.Development().fit_transform(medmal_paid)
medmal_paid = cl.TailCurve().fit_transform(medmal_paid)

# Benktander Model
benk = cl.Benktander()

# Prep Benktander Grid Search with various assumptions, and a scoring function
param_grid = dict(n_iters=list(range(1,100,2)),
apriori=[0.50, 0.75, 1.00])
scoring = {'IBNR':lambda x: x.ibnr_.sum()[0]}
grid = cl.GridSearch(benk, param_grid, scoring=scoring)
# Perform Grid Search
grid.fit(medmal_paid, sample_weight=medmal_prem)

# Plot data
grid.results_.pivot(index='n_iters', columns='apriori', values='IBNR').plot()
plt.title('Benktander convergence to Chainladder')
g = plt.ylabel('IBNR')
1 change: 1 addition & 0 deletions docs/auto_examples/plot_benktander.py.md5
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7d348baf6a5767e0aa7b52f411601199
Loading

0 comments on commit d082de7

Please sign in to comment.