Creating premium table¶
This notebook shows how to create the premium table from BasicTerm_M
model to be used in BasicTerm_SE
and BasicTerm_ME
.
To calculate premiums, the present values of claims and annuities need to be taken at the beginning of the policy terms, but BasicTerm_SE
and BasicTerm_ME
start projections for in-force model points at time zero after their issues, so the present values are not available. Such being the case, a premium rate table needs to be fed into the models. This notebook demonstrates how to create the premium table using BasicTerm_M
model.
By default, BasicTerm_M
and BasicTerm_ME
models the same product using the same assumption, and BasicTerm_M
is the new business version of BasicTerm_ME.
Here’re the steps to create the premium table.
Read the
BasicTerm_M
model.Replace the model point table with the one for the premium table. By default, the premium rates vary only by
age_at_entry
andpolicy_term
. The range ofage_at_entry
is 20 to 59, andpolicy_term
takes the value of either 10, 15 or 20. The model point data for the premium table is created from the combinations of the two attributes.Calculate per-policy premiums for the model points.
Create the premium table by processing the result of the above.
[1]:
import itertools
import modelx as mx
import pandas as pd
The code below reads the BasicTerm_M
model and assign it to model
and the Pojection
space to space
for later use.
[2]:
model = mx.read_model('BasicTerm_M')
space = model.Projection
The code below creates the model point table for the premium table. To calculate the premium rates as premium per sum assured, 1’s are entered in the sum_assured
column.
[3]:
df = pd.DataFrame(itertools.product(range(20, 60), [10, 15, 20]), columns=['age_at_entry', 'policy_term'])
df.index += 1
df.index.name = 'point_id'
df["sum_assured"] = 1
df
[3]:
age_at_entry | policy_term | sum_assured | |
---|---|---|---|
point_id | |||
1 | 20 | 10 | 1 |
2 | 20 | 15 | 1 |
3 | 20 | 20 | 1 |
4 | 21 | 10 | 1 |
5 | 21 | 15 | 1 |
... | ... | ... | ... |
116 | 58 | 15 | 1 |
117 | 58 | 20 | 1 |
118 | 59 | 10 | 1 |
119 | 59 | 15 | 1 |
120 | 59 | 20 | 1 |
120 rows × 3 columns
The code below replaces the default model point table with the new one just created above.
[4]:
space.model_point_table = df
Since the sum assured of all the model points are all 1, premium_pp
returns 0 because of the rounding operation in its formula. Below defines the premium_rate
by modifying the premium_pp
formula and removing the rounding so that the formula can be used for creating the premium rates.
[5]:
space.premium_pp.formula
[5]:
def premium_pp():
"""Monthly premium per policy
Monthly premium amount per policy defined as::
round((1 + loading_prem()) * net_premium(), 2)
.. versionchanged:: 0.2.0
The ``t`` parameter is removed.
.. seealso::
* :func:`loading_prem`
* :func:`net_premium_pp`
"""
return np.around((1 + loading_prem()) * net_premium_pp(), 2)
[6]:
@mx.defcells
def premium_rate():
return (1 + loading_prem()) * net_premium_pp()
[7]:
premium_rate()
[7]:
array([4.64097542e-05, 5.20142069e-05, 5.74162410e-05, 4.76584950e-05,
5.35875249e-05, 5.93504754e-05, 4.90032815e-05, 5.52810109e-05,
6.14332619e-05, 5.04508083e-05, 5.71035347e-05, 6.36761718e-05,
5.20083923e-05, 5.90648080e-05, 6.60919024e-05, 5.36840347e-05,
6.11754713e-05, 6.86943971e-05, 5.54864901e-05, 6.34471903e-05,
7.14989789e-05, 5.74253436e-05, 6.58927638e-05, 7.45224992e-05,
5.95110960e-05, 6.85262433e-05, 7.77835053e-05, 6.17552588e-05,
7.13630677e-05, 8.13024264e-05, 6.41704608e-05, 7.44202123e-05,
8.51017838e-05, 6.67705658e-05, 7.77163572e-05, 8.92064251e-05,
6.95708052e-05, 8.12720745e-05, 9.36437881e-05, 7.25879257e-05,
8.51100388e-05, 9.84441965e-05, 7.58403545e-05, 8.92552633e-05,
1.03641193e-04, 7.93483847e-05, 9.37353646e-05, 1.09271914e-04,
8.31343827e-05, 9.85808605e-05, 1.15377512e-04, 8.72230213e-05,
1.03825505e-04, 1.22003627e-04, 9.16415414e-05, 1.09506665e-04,
1.29200929e-04, 9.64200458e-05, 1.15665745e-04, 1.37025717e-04,
1.01591830e-04, 1.22348667e-04, 1.45540604e-04, 1.07193757e-04,
1.29606410e-04, 1.54815292e-04, 1.13266673e-04, 1.37495622e-04,
1.64927437e-04, 1.19855887e-04, 1.46079307e-04, 1.75963645e-04,
1.27011700e-04, 1.55427611e-04, 1.88020582e-04, 1.34790017e-04,
1.65618702e-04, 2.01206244e-04, 1.43253028e-04, 1.76739777e-04,
2.15641388e-04, 1.52469982e-04, 1.88888191e-04, 2.31461155e-04,
1.62518071e-04, 2.02172755e-04, 2.48816911e-04, 1.73483423e-04,
2.16715197e-04, 2.67878332e-04, 1.85462240e-04, 2.32651824e-04,
2.88835763e-04, 1.98562080e-04, 2.50135419e-04, 3.11902899e-04,
2.12903328e-04, 2.69337392e-04, 3.37319808e-04, 2.28620863e-04,
2.90450228e-04, 3.65356364e-04, 2.45865958e-04, 3.13690280e-04,
3.96316114e-04, 2.64808454e-04, 3.39300945e-04, 4.30540656e-04,
2.85639234e-04, 3.67556282e-04, 4.68414557e-04, 3.08573055e-04,
3.98765135e-04, 5.10370897e-04, 3.33851788e-04, 4.33275832e-04,
5.56897468e-04, 3.61748118e-04, 4.71481528e-04, 6.08543708e-04])
The code below creates the premium table as a Series indexed by age_at_entry
and policy_term
from the result above. The table is created by modifying the copy of the model point table and assigning the result of premium_rate
above.
[8]:
premium_rate_table = df.copy()
premium_rate_table["premium_rate"] = space.premium_rate()
del premium_rate_table["sum_assured"]
premium_rate_table.set_index(["age_at_entry", "policy_term"], inplace=True)
premium_rate_table["premium_rate"] # As Series
[8]:
age_at_entry policy_term
20 10 0.000046
15 0.000052
20 0.000057
21 10 0.000048
15 0.000054
...
58 15 0.000433
20 0.000557
59 10 0.000362
15 0.000471
20 0.000609
Name: premium_rate, Length: 120, dtype: float64