{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to fastlife\n", "\n", "This notebooks explores the fastlife model, a parallel processing model, by taking a closer look at some of the Spaces unique to the fastlife model.\n", "\n", "If you're viewing this page as a static HTML page on https://lifelib.io, the same contents are also available [here on binder] as Jupyter notebook executable online (it may take a while to load). To run this notebook and get all the outputs below, Go to the **Cell** menu above, and then click **Run All**.\n", "\n", "[here on binder]: https://mybinder.org/v2/gh/fumitoh/lifelib/binder?filepath=lifelib%2Fprojects%2Ffastlife%2Ffastlife-introduction.ipynb" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Reading the fastlife model\n", "\n", "The fastlife model is saved as a folder named *model* in the fastlife folder. To create a live model, import **modelx** and call ``read_model`` function by passing the folder path." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import modelx as mx\n", "model = mx.read_model(\"model\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The previously created model is renamed automatically to avoid name conflict. To get all existing models, ``get_models`` modelx API function can be used. ``get_models`` returns a dict of all the existing models associated with their names." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'fastlife': }" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import modelx as mx\n", "mx.get_models()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculating the results in the Projection Space\n", "\n", "The present values of net cashflows are calculated in ``PV_NetCashsflow`` Cells in the ``Projection`` Space. " ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Policy\n", "1 8.954018e+03\n", "2 7.511092e+03\n", "3 9.173907e+03\n", "4 7.638071e+03\n", "5 9.418541e+03\n", " ... \n", "296 2.599794e+06\n", "297 2.298079e+06\n", "298 2.557191e+06\n", "299 2.242406e+06\n", "300 2.510715e+06\n", "Length: 300, dtype: float64" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.PV_NetCashflow(0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike the **simplelife** model, ``PV_NetCashflow`` returns a pandas Seris object with Policy index. Each element of the returned Series is the present value of the net cashflow of each model point. Below is the formula of ``PV_NetCashflow``." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "def PV_NetCashflow(t):\n", " \"\"\"Present value of net cashflow\"\"\"\n", " return (PV_PremIncome(t)\n", " + PV_ExpsTotal(t)\n", " + PV_BenefitTotal(t))" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.PV_NetCashflow.formula" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you see, ``PV_NetCashflow`` at time 0 is the sum of ``PV_PremIncome``, ``PV_ExpsTotal`` and ``PV_BenefitTotal``." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Policy\n", "1 2.932812e+04\n", "2 2.418886e+04\n", "3 3.019898e+04\n", "4 2.466945e+04\n", "5 3.118342e+04\n", " ... \n", "296 3.218643e+06\n", "297 3.066867e+06\n", "298 3.198456e+06\n", "299 3.038678e+06\n", "300 3.176323e+06\n", "Name: PV_PremIncome, Length: 300, dtype: float64" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.PV_PremIncome(0)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "def PV_PremIncome(t):\n", " \"\"\"Present value of premium income\"\"\"\n", "\n", " exist = (t <= last_t())\n", "\n", " if not exist.any():\n", " return 0\n", " else:\n", " result = exist * PremIncome(t) + PV_PremIncome(t+1) / (1 + DiscRate(t))\n", " result.name = \"PV_PremIncome\"\n", " return result" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.PV_PremIncome.formula" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of the Cells in ``Projection`` Space operate on Serieses indexed by Policy just like ``PV_NetCashflow``, because their precedent Cells operate on Serieses with the same index." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Policy Space" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``Projection`` Space have a child Space named ``Policy``. ``Policy`` contains policy data and Cells to calculate policyholder values. The ``PolicyData`` Reference holds a ``PandasData`` object, which internaly stores policy data read from an input file as a pandas DataFrame." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Policy.PolicyData" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get the DataFrame stored in the `PolicyData` object, call it:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ProductPolicyTypeGenChannelDurationSexIssueAgePaymentModePremFreqPolicyTermMaxPolicyTermPolicyCountSumAssured
Policy
1TERM11NaN0M30112156511000000
2TERM11NaN0F30112156511000000
3TERM11NaN0M31112156411000000
4TERM11NaN0F31112156411000000
5TERM11NaN0M32112156311000000
..........................................
296ENDW11NaN0F77112101011000000
297ENDW11NaN0M78112101011000000
298ENDW11NaN0F78112101011000000
299ENDW11NaN0M79112101011000000
300ENDW11NaN0F79112101011000000
\n", "

300 rows × 13 columns

\n", "
" ], "text/plain": [ " Product PolicyType Gen Channel Duration Sex IssueAge PaymentMode \\\n", "Policy \n", "1 TERM 1 1 NaN 0 M 30 1 \n", "2 TERM 1 1 NaN 0 F 30 1 \n", "3 TERM 1 1 NaN 0 M 31 1 \n", "4 TERM 1 1 NaN 0 F 31 1 \n", "5 TERM 1 1 NaN 0 M 32 1 \n", "... ... ... ... ... ... .. ... ... \n", "296 ENDW 1 1 NaN 0 F 77 1 \n", "297 ENDW 1 1 NaN 0 M 78 1 \n", "298 ENDW 1 1 NaN 0 F 78 1 \n", "299 ENDW 1 1 NaN 0 M 79 1 \n", "300 ENDW 1 1 NaN 0 F 79 1 \n", "\n", " PremFreq PolicyTerm MaxPolicyTerm PolicyCount SumAssured \n", "Policy \n", "1 12 15 65 1 1000000 \n", "2 12 15 65 1 1000000 \n", "3 12 15 64 1 1000000 \n", "4 12 15 64 1 1000000 \n", "5 12 15 63 1 1000000 \n", "... ... ... ... ... ... \n", "296 12 10 10 1 1000000 \n", "297 12 10 10 1 1000000 \n", "298 12 10 10 1 1000000 \n", "299 12 10 10 1 1000000 \n", "300 12 10 10 1 1000000 \n", "\n", "[300 rows x 13 columns]" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Policy.PolicyData()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "``PolicyData`` is a `PandasData` object, and it was created by the [new_pandas](https://docs.modelx.io/en/latest/reference/space/generated/modelx.core.space.UserSpace.new_pandas.html) method of `UserSpace`. The location of the input file can be acquired as its `path` attribute." ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "WindowsPath('Input/PoliyData.xlsx')" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Policy.PolicyData.path" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many Cells in `Policy` whose roles are for calculating policyholder values such as premiums and cash surrender values from commutation functions and actuarial notations. \n", "For example, `GrossPremRate` is for calculating gross premium rates: " ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "def GrossPremRate():\n", " \"\"\"Gross Premium Rate per Sum Assured per payment\"\"\"\n", "\n", " def get_value(pol):\n", "\n", " prod = pol['Product']\n", " alpha = pol['LoadAcqSA']\n", " beta = pol['LoadMaintPrem']\n", " delta = pol['LoadMaintPrem2']\n", " gamma = pol['LoadMaintSA']\n", " gamma2 = pol['LoadMaintSA2']\n", " freq = pol['PremFreq']\n", "\n", " x, n, m = pol['IssueAge'], pol['PolicyTerm'], pol['PolicyTerm']\n", "\n", " comf = LifeTable[pol['Sex'], pol['IntRate_PREM'], pol['TableID_PREM']]\n", "\n", " if prod == 'TERM' or prod == 'WL':\n", " return (comf.Axn(x, n) + alpha + gamma * comf.AnnDuenx(x, n, freq)\n", " + gamma2 * comf.AnnDuenx(x, n-m, 1, m)) / (1-beta-delta) / freq / comf.AnnDuenx(x, m, freq)\n", "\n", " elif prod == 'ENDW':\n", " return (comf.Exn(x, n) + comf.Axn(x, n) + alpha + gamma * comf.AnnDuenx(x, n, freq)\n", " + gamma2 * comf.AnnDuenx(x, n-m, 1, m)) / (1-beta-delta) / freq / comf.AnnDuenx(x, m, freq)\n", " else:\n", " raise ValueError('invalid product')\n", "\n", "\n", " result = PolicyDataExt1().apply(get_value, axis=1)\n", " result.name = 'GrossPremRate'\n", "\n", " return result" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Policy.GrossPremRate.formula" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we see in the `Projection` Space, `GrossPremRate` also retuns results for all model points in a Series with the Policy index." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Policy\n", "1 0.000298\n", "2 0.000245\n", "3 0.000307\n", "4 0.000250\n", "5 0.000317\n", " ... \n", "296 0.043845\n", "297 0.045945\n", "298 0.044096\n", "299 0.046412\n", "300 0.044383\n", "Name: GrossPremRate, Length: 300, dtype: float64" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Policy.GrossPremRate()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Assumptions Space" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Projection` has another space named `Assumptions`. `Assumptions` associates projection assumptions to model points, by looking up paramters in a table stored as an `ExcelRange` object associated to a Reference named `Assumption`." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Assumptions.Assumption" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just like `PandasData` objects, `Assumption` has the `path` attribute hoding a path to its input file." ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "WindowsPath('Input/input.xlsx')" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Assumptions.Assumption.path" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`Assumption` is a dict-like object, whose keys are tuples of assumption type, product ID, policy type ID and genration ID. For example, For the assumption type 'Surrender' and product 'TERM'" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'LapseRate1'" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Assumptions.Assumption[\"Surrender\", \"TERM\", None, None]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of the Cells in the `Assumption` Space are for lookup operations just like the above example. The lookup results are also in Series." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Policy\n", "1 LapseRate1\n", "2 LapseRate1\n", "3 LapseRate1\n", "4 LapseRate1\n", "5 LapseRate1\n", " ... \n", "296 LapseRate1\n", "297 LapseRate1\n", "298 LapseRate1\n", "299 LapseRate1\n", "300 LapseRate1\n", "Length: 300, dtype: object" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.Projection.Assumptions.SurrRateID()" ] } ], "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.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }