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 and policy_term. The range of age_at_entry is 20 to 59, and policy_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.

Click the badge below to run this notebook online on Google Colab. You need a Google account and need to be logged in to it to run this notebook on Google Colab. Run on Google Colab

The next code cell below is relevant only when you run this notebook on Google Colab. It installs lifelib and creates a copy of the library for this notebook.

[1]:
import sys, os

if 'google.colab' in sys.modules:
    lib = 'basiclife'; lib_dir = '/content/'+ lib
    if not os.path.exists(lib_dir):
        !pip install lifelib
        import lifelib; lifelib.create(lib, lib_dir)

    %cd $lib_dir

The next code imports the necessary Python modules.

[2]:
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.

[3]:
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.

[4]:
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
[4]:
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.

[5]:
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.

[6]:
space.premium_pp.formula
[6]:
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)
[7]:
@mx.defcells
def premium_rate():
    return (1 + loading_prem()) * net_premium_pp()
[8]:
premium_rate()
[8]:
array([4.64097874e-05, 5.20142609e-05, 5.74163309e-05, 4.76585304e-05,
       5.35875832e-05, 5.93505736e-05, 4.90033193e-05, 5.52810740e-05,
       6.14333696e-05, 5.04508489e-05, 5.71036033e-05, 6.36762900e-05,
       5.20084360e-05, 5.90648826e-05, 6.60920324e-05, 5.36840817e-05,
       6.11755527e-05, 6.86945406e-05, 5.54865410e-05, 6.34472793e-05,
       7.14991376e-05, 5.74253987e-05, 6.58928613e-05, 7.45226753e-05,
       5.95111559e-05, 6.85263505e-05, 7.77837009e-05, 6.17553240e-05,
       7.13631858e-05, 8.13026444e-05, 6.41705320e-05, 7.44203428e-05,
       8.51020274e-05, 6.67706437e-05, 7.77165017e-05, 8.92066979e-05,
       6.95708907e-05, 8.12722349e-05, 9.36440944e-05, 7.25880198e-05,
       8.51102174e-05, 9.84445414e-05, 7.58404584e-05, 8.92554627e-05,
       1.03641583e-04, 7.93484996e-05, 9.37355878e-05, 1.09272355e-04,
       8.31345102e-05, 9.85811110e-05, 1.15378012e-04, 8.72231632e-05,
       1.03825787e-04, 1.22004196e-04, 9.16416996e-05, 1.09506983e-04,
       1.29201578e-04, 9.64202228e-05, 1.15666105e-04, 1.37026460e-04,
       1.01592029e-04, 1.22349075e-04, 1.45541457e-04, 1.07193980e-04,
       1.29606875e-04, 1.54816273e-04, 1.13266925e-04, 1.37496152e-04,
       1.64928569e-04, 1.19856171e-04, 1.46079913e-04, 1.75964954e-04,
       1.27012023e-04, 1.55428306e-04, 1.88022101e-04, 1.34790385e-04,
       1.65619502e-04, 2.01208012e-04, 1.43253447e-04, 1.76740699e-04,
       2.15643451e-04, 1.52470461e-04, 1.88889258e-04, 2.31463569e-04,
       1.62518620e-04, 2.02173994e-04, 2.48819743e-04, 1.73484055e-04,
       2.16716638e-04, 2.67881664e-04, 1.85462968e-04, 2.32653505e-04,
       2.88839696e-04, 1.98562923e-04, 2.50137387e-04, 3.11907554e-04,
       2.12904306e-04, 2.69339702e-04, 3.37325333e-04, 2.28622001e-04,
       2.90452947e-04, 3.65362941e-04, 2.45867287e-04, 3.13693489e-04,
       3.96323966e-04, 2.64810009e-04, 3.39304745e-04, 4.30550057e-04,
       2.85641059e-04, 3.67560794e-04, 4.68425846e-04, 3.08575204e-04,
       3.98770509e-04, 5.10384491e-04, 3.33854326e-04, 4.33282251e-04,
       5.56913884e-04, 3.61751124e-04, 4.71489217e-04, 6.08563590e-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.

[9]:
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
[9]:
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