0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

アクチュアリーのためのPython入門(死亡リスク額の計算2)

0
Last updated at Posted at 2026-05-12

アクチュアリーのためのPython入門(保険数理モデリング編第7回)

死亡リスク額の計算2

📚 アクチュアリーのためのPython入門
この記事は保険数理モデリング編の一部です。
目次はこちら
逆引きガイドはこちら

はじめに

前回は、死亡ストレスを与えた場合の現在推計と、
1年後の死亡ストレス後の現在推計を計算しました。

今回は、それを一般化し、
t年後の死亡ストレスありの現在推計を計算します。

また、t年後の標準の現在推計も計算し、
t年後の死亡リスクも計算できるようにします。

キャッシュフローの修正

キャッシュフローの計算するファイルcashflow_mort.pyでは、
死亡ストレス部分を修正します。
引数にストレスを与える年度と、
ストレスありとなしを選択できる値を加えます。

cashflow_mort.py
# 死亡ストレスの計算(mode=0:ストレスなし,1:ストレスあり)
def mort_stress(policy_y, t, stress_y, mode):
    if mode == 0:
        str = 1
    else:
        if policy_y + t >= stress_y:
            str = 1.125
        else:
            str = 1
    return str

また、キャッシュフローを計算する関数create_cashflowにも、
同様に引数にstress_yearmodeを加えます。
ここでは、デフォルト値も与えておきます。

cashflow_mort.py
# キャッシュフロー計算の関数化 base_yearは計算基準年度
def create_cashflow(base_year = 2022, stress_year = 2023, mode = 0):    

残存表の死亡率に、
先に作成した死亡ストレスの結果を乗じます。

cashflow_mort.py
# 生命表の作成
        for t in range(n):
            str = mort_stress(policy, t, stress_year ,mode)
            q = qdx(sex, age + t)
            w = qwx(product, t, m)
            next_d = lx[-1] * q * mort_k(product) * str
            next_w = lx[-1] * w
            if t == n - 1:
                next_m = lx[-1] - next_d - next_w
                next_l = 0
            else:
                next_m = 0
                next_l = lx[-1] - next_d - next_w

他は今までと同じです。
以下に、コード全体も載せておきます。

cashflow_mort.py
# t年経過後の死亡リスク(一般化)
from core import *
from endowment import PremE, SVE
from term import PremT, SVT
from whole import PremW, SVW
import pandas as pd

# 死亡指数の関数化
def mort_k(product):
    match product:
        case "E":
            k = 0.8
        case "T":
            k = 0.7
        case "W":
            k = 0.85
    return k

# 死亡率の関数
def qdx(sex, age):
    return qx[sex][age]

# 保険料の計算式
premium_func = {
    "E":PremE,
    "T":PremT,
    "W":PremW
}
def prem_func(product, sex, age, term):
    return premium_func[product](sex, age, term)

# 解約率(養老保険)
def qwxE(t, m):
    if t == 0:
        w = 0.05
    elif t < 3:
        w = 0.03
    else:
        w = 0.02
    return w

# 解約率(定期保険)
def qwxT(t, m):
    if t == 0:
        w = 0.08
    elif t < 3:
        w = 0.05
    else:
        w = 0.03
    return w

# 解約率(終身保険)
def qwxW(t, m):
    if t == 0:
        w = 0.03
    elif t >= m:
        w = 0.01
    else:
        w = 0.02
    return w

# 解約率の関数
surrender_func = {
    "E":qwxE,
    "T":qwxT,
    "W":qwxW
}
def qwx(product, t, m):
    return surrender_func[product](t, m)

# 解約返戻金の計算式
surrendervalue_func = {
    "E":SVE,
    "T":SVT,
    "W":SVW
}
def sv_func(product, sex, age, term ,t):
    return surrendervalue_func[product](sex, age, term, t)

# 満期保険金
def maturity(product):
    if product == "T":
        value = 0   # 定期保険は0
    else:
        value = 1   # 他は1
    return value

# 最終年齢(終身保険用)
def omega(sex):
    o = len(qx[sex]) - 1
    return o

# 保険料払込期間
def PremPeriod(product, sex, age, term):
    n = parse_term(term, age)
    return n

# 保険期間
def InsPeriod(product, sex, age, term):
    if product == "W":
        value = omega(sex) - age       # 終身は最終年齢 
    else:
        value = parse_term(term, age)  # 他はそのまま
    return value

# 死亡ストレスの計算(mode=0:ストレスなし,1:ストレスあり)
def mort_stress(policy_y, t, stress_y, mode):
    if mode == 0:
        str = 1
    else:
        if policy_y + t >= stress_y:
            str = 1.125
        else:
            str = 1
    return str

# キャッシュフロー計算の関数化 base_yearは計算基準年度
def create_cashflow(base_year = 2022, stress_year = 2023, mode = 0):    

    # 結果を入れる変数
    results1 = []

    df = pd.read_excel("contr_all.xlsx")

    for _, row in df.iterrows():
        product = row["product"]
        policy = int(row["policy"])
        sex = row["sex"]
        age = int(row["age"])
        term = row["term"]
        amount = int(row["amount"])

        # 保険収支の計算
        l0 = amount      # 初期保険金額

        # 残存表の作成
        lx = [l0]        # 保有保険金額
        dx = []          # 死亡保険金額
        wx = []          # 解約保険金額
        mx = []          # 満期保険金額

        n = InsPeriod(product, sex, age, term) # 保険期間
        m = PremPeriod(product, sex, age, term) # 保険料払込期間
        # 生命表の作成
        for t in range(n):
            str = mort_stress(policy, t, stress_year ,mode)
            q = qdx(sex, age + t)
            w = qwx(product, t, m)
            next_d = lx[-1] * q * mort_k(product) * str
            next_w = lx[-1] * w
            if t == n - 1:
                next_m = lx[-1] - next_d - next_w
                next_l = 0
            else:
                next_m = 0
                next_l = lx[-1] - next_d - next_w

            lx.append(next_l)
            dx.append(next_d)
            wx.append(next_w)
            mx.append(next_m)

        # 保険収支の項目
        inprem = []    # 保険料収入
        benefit = []   # 保険金支払い
        surrender = [] # 解約返戻金支払い
        expenses = []  # 事業費
        cashflow = []  # キャッシュフロー

        P = float(prem_func(product, sex, age, term))

        # キャッシュフローの計算
        for t in range(n):
            # 保険料の収入
            if t < m:
                inprem.append(lx[t] * P)
            else:
                inprem.append(0)
            # 保険金の支払い
            if t == n - 1:
                # 死亡+満期保険金の支払い
                pay_ben = dx[t] + mx[t] * maturity(product)
            else:
                # 死亡保険金の支払い
                pay_ben = dx[t]
            benefit.append(pay_ben)
            # 解約返戻金の支払い
            W = float(sv_func(product, sex, age, term, t + 1))
            surrender.append(wx[t] * W)
            # 事業費の支払い
            expenses.append(inprem[t] * 0.3)
            # キャッシュフロー
            cashflow.append(benefit[t] +surrender[t] \
                      + expenses[t] - inprem[t])

            # 補整値の計算
            af = amount / lx[base_year - policy + 1]

            # 商品別のキャッシュフロー
            results1.append({"product":product,
                             "year":policy + t,
                             "benefit":int(benefit[t] * af),
                             "surrender":int(surrender[t] * af), 
                             "expenses":int(expenses[t] * af),
                             "inprem":int(inprem[t] * af),
                             "cashflow":int(cashflow[t] * af)
            })

    result_df = pd.DataFrame(results1)
    # 商品別の集計
    grouped_product = result_df.groupby(["product", "year"]).sum()
    summary_product = grouped_product.reset_index()

    # 合計の集計
    grouped_total = result_df.groupby("year").sum()
    summary_total = grouped_total.reset_index()
    # Totalのラベルを付ける
    summary_total["product"] = "Total"

    # 結合
    summary = pd.concat([summary_product, summary_total], ignore_index=True)
    # 年度のフィルタ
    summary = summary[summary["year"] >= base_year + 1]
    return summary

# キャッシュフローの出力
if __name__ == "__main__":
    summary = create_cashflow()
    summary.to_excel("result_mort.xlsx", index=False)

現在推計の修正

続いて、現在推計を計算するファイルpresentvalue_mort.pyです。
こちらは修正点が多いので、全文を区切りながら載せます。

まずは、死亡リスク額をデータフレーム化するため、
ここではpandasを使います。
金利は前回と同じです。

presentvalue_mort.py
# t年経過後死亡リスク(一般化)
from core import *
from cashflow_mort import create_cashflow
import pandas as pd

rate0 = [
    0.00178,0.00295,0.00328,0.00400,0.00478,0.00519,0.00588,0.00680,0.00769,0.00877,
    0.00972,0.01053,0.01129,0.01204,0.01283,0.01367,0.01452,0.01532,0.01605,0.01667,
    0.01718,0.01759,0.01795,0.01827,0.01856,0.01885,0.01914,0.01944,0.01977,0.02012,
    0.02051,0.02092,0.02135,0.02178,0.02221,0.02263,0.02305,0.02345,0.02384,0.02421,
    0.02458,0.02492,0.02526,0.02558,0.02590,0.02619,0.02648,0.02676,0.02702,0.02728,
    0.02753,0.02776,0.02799,0.02821,0.02842,0.02863,0.02883,0.02902,0.02920,0.02938,
    0.02956,0.02972,0.02988,0.03004,0.03019,0.03034,0.03049,0.03063,0.03076,0.03089,
    0.03102,0.03114,0.03126,0.03138,0.03150,0.03161,0.03172,0.03182,0.03193,0.03203,
    0.03212,0.03222,0.03231,0.03240,0.03249,0.03258,0.03267,0.03275,0.03283
    ]

現価率はフォワードレートを使います。
s年後のt年金利を計算し、そこから現価率を計算します。
(tは0からはじまるので乗数は+1していることに注意してください)

presentvalue_mort.py
# 現価率(s年経過後のt年金利)
def DF(s, t):
    if s + t < len(rate0):
        r1 = rate0[s + t]
    else:
        r1 = rate0[-1]
    r0 = rate0[s-1]
    fr = (((1 + r1) ** (s + t + 1))/(1 + r0) ** s) ** (1/(t+1))
    value = fr ** (-t-0.5)
    return value

続いて、現在推計の計算です。
ストレス開始年度やストレスありなしを変更しながら
現在推計を計算するので関数化します。

死亡ストレス対象外の期間exclude_tを設定します。
base_year=2022, stress_year=2023なら0
base_year=2022, stress_year=2024なら1
$\cdots$
となるようにします。

また、経過年数tを0からはじまるように付け直します。

現在推計の計算用の現価率は修正したDF関数を使います。

presentvalue_mort.py
# base_year:計算基準年度
# stress_year:ストレス開始年度
# mode:(0:ストレスあり、1:ストレスなし)
def present_value(base_year, stress_year, mode):
    # キャッシュフローの計算
    summary = create_cashflow(base_year, stress_year, mode)
    # 死亡ストレス対象外の期間
    exclude_t = stress_year - base_year - 1
    # Totalのみ抽出
    summary = summary[summary["product"] == "Total"]
    # ストレス年度以降を抽出
    summary = summary[summary["year"] >= stress_year]
    # 経過年数を追加
    summary["t"] = summary["year"] - base_year - exclude_t - 1
    # 現在価値を計算
    PV = 0 
    for _, row in summary.iterrows():
        t = int(row["t"])
        cf = int(row["cashflow"])
        PV += cf * DF(exclude_t, t)
    return PV

現在推計を計算する関数ができましたので、
あとはfor文でループさせて死亡リスク額を計算ます。
死亡リスクを入れるリストmort_riskを初期化。
計算基準年度を2022で固定しています。

iを0~9までfor文で回し、0年後から9年後までの
死亡リスク額を計算します。

2つ目のfor文で、死亡ストレスなしの現在推計と
死亡ストレスありの現在推計を計算します。

最後にmort_riskへそれぞれの値を追加し、リスト化します。

presentvalue_mort.py
mort_risk = []
base_year = 2022
for i in range(10):
    year = base_year + i + 1
    PV = []
    for j in range(2):
        PV.append(present_value(base_year, year, j))
    mort_risk.append({"t":i,
                     "Curent_Estimate":int(PV[0]),
                     "Mortality_up":int(PV[1]),
                     "Mortality_risk":int(PV[1] - PV[0])})

また、pandasを使ってデータフレーム化します。
ここでは、期間が短いので内容をprintで出力します。

presentvalue_mort.py
mort_chrono = pd.DataFrame(mort_risk)
print(mort_chrono)

結果は次のようになります。tは経過年度なので、
t=0は計算基準年度での死亡リスク額、
t=1は1年後の死亡リスク額、
t=2は2年後の死亡リスク額というようになります。

   t  Curent_Estimate  Mortality_up  Mortality_risk
0  0           812213        977670          165457
1  1          1488397       1648879          160482
2  2          2133682       2289428          155745
3  3          2745382       2896185          150802
4  4          3331089       3477018          145929
5  5          3892174       4033154          140980
6  6          4421658       4557269          135610
7  7          2753029       2883826          130797
8  8          3106192       3232290          126097
9  9          3303445       3424758          121312

まとめ

今回は、t年後の死亡リスク額を計算できるように、
前回まで計算した内容を一般化しました。

すぐに一般化するのは難しいので、
実際の数値例をいくつか計算して、
それから一般化していくのが分かりやすいかと思います。

実務では、こういった計算を将来収支の中に組み込んで、
将来の経済価値ベースの指標(ESR)を計算したり、
保険負債に含まれるMOCEの計算に使ったりします。

Pythonだけですぐに内容を理解するのは難しいので、
Excelなどでもっと簡単なモデルでも計算して理解を深めてみましょう。


📚 ナビゲーション
前の記事
死亡リスク額の計算1

次の記事
月次キャッシュフロー1

📚 目次
アクチュアリーのためのPython入門

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?