Source code for appliedlife.IntegratedLife.Mortality
"""Mortality tables
The :mod:`~appliedlife.IntegratedLife.Mortality` space reads
mortality tables from a mortality file
and creates a unified mortality table as a pandas Series
indexed with Table ID, Attained Age and Duration.
This space is referenced as :attr:`~appliedlife.IntegratedLife.ProductBase.mort_data`
in the :mod:`~appliedlife.IntegratedLife.ProductBase` space.
Attributes:
base_data: Reference to the :mod:`~appliedlife.IntegratedLife.BaseData` space
Example:
The sample code below demonstrates how to examine the contents of
:mod:`~appliedlife.IntegratedLife.Mortality`.
.. code-block:: python
>>> import modelx as mx
>>> m = mx.read_model("IntegratedLife")
>>> m.Mortality.mort_file()
WindowsPath('C:/Users/User1/appliedlife/input_tables/mortality_tables.xlsx')
>>> m.Mortality.table_defs()
is_used sex ... has_select description
table_id ...
T3363 True M ... True 2017 Unloaded CSO Composite Male ALB
T3364 True F ... True 2017 Unloaded CSO Composite Female ALB
T3275 True M ... True 2015 VBT Unismoke Male ALB
T3276 True F ... True 2015 VBT Unismoke Female ALB
T884 True F ... False Annuity 2000 Basic Female
T885 True M ... False Annuity 2000 Basic Male
>>> m.Mortality.select_table('T3276')
0 1 2 3 ... 21 22 23 24
0 0.00022 0.00012 0.00008 0.00007 ... 0.00029 0.00032 0.00035 0.00036
1 0.00012 0.00008 0.00007 0.00007 ... 0.00032 0.00035 0.00036 0.00036
2 0.00008 0.00007 0.00007 0.00007 ... 0.00035 0.00036 0.00036 0.00035
3 0.00007 0.00007 0.00007 0.00007 ... 0.00036 0.00036 0.00035 0.00035
4 0.00007 0.00007 0.00007 0.00007 ... 0.00036 0.00035 0.00035 0.00036
.. ... ... ... ... ... ... ... ... ...
91 0.02529 0.06300 0.13175 0.16683 ... 0.50000 0.50000 0.50000 0.50000
92 0.03682 0.09384 0.16683 0.18406 ... 0.50000 0.50000 0.50000 0.50000
93 0.05460 0.12337 0.18406 0.20412 ... 0.50000 0.50000 0.50000 0.50000
94 0.08008 0.16292 0.20412 0.22599 ... 0.50000 0.50000 0.50000 0.50000
95 0.11495 0.20412 0.22599 0.24952 ... 0.50000 0.50000 0.50000 0.50000
[96 rows x 25 columns]
>>> m.Mortality.merged_table('T3276')
att_age duration
0 0 0.00022
1 1 0.00012
2 2 0.00008
3 3 0.00007
4 4 0.00007
116 25 0.50000
117 25 0.50000
118 25 0.50000
119 25 0.50000
120 25 0.50000
Length: 2521, dtype: float64
>>> m.Mortality.unified_table()
table_id att_age duration
T3363 0 0 0.00019
1 1 0.00012
2 2 0.00011
3 3 0.00009
4 4 0.00009
T885 116 0 1.00000
117 0 1.00000
118 0 1.00000
119 0 1.00000
120 0 1.00000
Length: 10326, dtype: float64
"""
from modelx.serialize.jsonvalues import *
_formula = None
_bases = []
_allow_none = None
_spaces = []
# ---------------------------------------------------------------------------
# Cells
[docs]
def merged_table(table_id: str):
"""Merged mortality table for a given table ID"""
has_select = table_defs().at[table_id, "has_select"]
has_ultimate = table_defs().at[table_id, "has_ultimate"]
if has_select:
select = select_table(table_id).stack()
select.name = "rate"
select.index.names = ["entry_age", "duration"]
select = select.reset_index()
select["att_age"] = select["entry_age"] + select["duration"]
select = select.set_index(["att_age", "duration"])["rate"]
if has_ultimate:
ultimate = ultimate_tables()[[table_id]].copy()
ultimate["duration"] = select_duration_len()[table_id]
ultimate = ultimate.set_index("duration", append=True)[table_id]
if has_select and has_ultimate:
return pd.concat([select, ultimate])
elif has_select and not has_ultimate:
return select
elif not has_select and has_ultimate:
return ultimate
else:
raise ValueError(f"Table {table_id} neither has select nor ultimate")
[docs]
def mort_file():
"""Mortality table file"""
dir_ = base_data.const_params().at["table_dir", "value"]
file = base_data.const_params().at["mort_file", "value"]
return _model.path.parent / dir_ / file
[docs]
def select_duration_len():
"""Selection period length"""
ids = table_defs().index
dur_len = []
for id_ in ids:
if table_defs().at[id_, "has_select"]:
dur_len.append(len(select_table(id_).columns))
else:
dur_len.append(0) # 0 for ultimate only
return pd.Series(dur_len, index=ids)
[docs]
def select_table(table_id: str):
"""Reads a select mortality table with the given table ID"""
df = pd.read_excel(
mort_file(),
sheet_name=table_id,
index_col=0)
df.columns = range(len(df.columns))
return df
[docs]
def table_defs():
"""Table definitions"""
df = pd.read_excel(
mort_file(),
sheet_name="TableDefs",
index_col=0)
return df.loc[df["is_used"] == True]
[docs]
def table_last_age():
"""Mortality table last age"""
return unified_table().index.to_frame(index=False).groupby("table_id")["att_age"].max()
[docs]
def ultimate_tables():
"""Reads the ultimate mortality tables"""
df = pd.read_excel(
mort_file(),
sheet_name="Ultimate",
index_col=0)
df.index.name = "att_age"
return df
[docs]
def unified_table():
"""Unified mortality table"""
return pd.concat(
{id_: merged_table(id_) for id_ in table_defs().index},
names=["table_id"]
)
# ---------------------------------------------------------------------------
# References
base_data = ("Interface", ("..", "BaseData"), "auto")