アクチュアリーのためのPython入門(第14回)
ファイルの構成の整理
📚 アクチュアリーのためのPython入門
この記事は入門編の一部です。
▶ 目次はこちら
はじめに
今回は大きな新機能をしません。
代わりに、これまで作成してきたコードの構造を整理します。
前回は、
- 保険料レートの作成
- 保険料積立金レートの作成
を行いました。
続いて、複数商品・複数年齢の将来収支まで行いたいのですが、
すべてを1つのファイルに書き続けると、
- コードが長くなる
- 役割が混在する
- 修正の影響範囲が見えにくくなる
などの問題が発生します。
そこで今回は、コードをその役割ごとにファイルで分割していきます。
今回のポイントについて
-
共通部分
まず、商品共通の部分を切り出します。- 死亡率
- 生命表
- 計算基数
- 収入現価・支出現価
- 端数処理のroundhu関数
- 年満期を変換するparse_term関数
これらは養老でも定期でも終身保険でも共通ですのです。
これを1つのファイルにします。
ここではcore.pyとしておきます。
-
次に商品固有のロジックは商品ごとに分けます。
- endowment.py
- term.py
- whole.py
それぞれのファイルでは、
- 保険料の計算
- 保険料積立金の計算
- 解約返戻金の計算
- 将来収支の計算前提
- 将来収支の計算
を扱います。
将来収支の計算前提と計算のロジックは、
いずれ別のファイルに切り離すかもしれませんが、
今回は分かりやすさを重視して、
商品ごとのファイルに入れておきます。
ファイルの構成について
- core.py
- endowment.py
- term.py
- whole.py
は同一の作業フォルダにおきます。
仮にフォルダ名をworkだとすると、
work/
├── core.py
├── endowment.py
├── term.py
└── whole.py
core.pyはコードを移行するだけなので、
特に注意する点はありません。
商品別のファイルの内容は、endowment.pyを例にあげます。
最初にcore.pyの内容を読み込むためのコードを置きます。
from core import *
あとは養老保険の
- 営業保険料
- 純保険料
- 保険料積立金
- 解約返戻金
を計算する関数を置きます。
# 養老保険
# 営業保険料の計算
def PremE(sex, start_age, term):
n = parse_term(term, start_age)
# 予定事業費
alpha = 0.025
delta = 0.02
gamma = 0.00215
beta = 0.03
# 営業保険料の計算
An = Axn(sex, start_age, n)
an = axn(sex, start_age, n)
value = (An + alpha + gamma * an) / ((1 - beta - delta) * an)
# 端数処理
value = roundhu(value, 6)
return value
# 純保険料の計算
def netPremE(sex, start_age, term):
n = parse_term(term, start_age)
return Axn(sex, start_age, n) / axn(sex, start_age, n)
# 保険料積立金の計算
def ResE(sex, start_age, term, t):
n = parse_term(term, start_age)
benefit = Axn(sex, start_age + t, n - t)
income = netPremE(sex, start_age, n) \
* axn(sex, start_age + t, n - t)
value = Decimal(str(benefit)) - Decimal(str(income))
return roundhu(value, 6)
# 解約返戻金の計算
def SVE(sex, start_age, n, t):
if t <= 10:
surrender_fact = 0.025 * (1 - t / min(n , 10))
else:
surrender_fact = 0
value = ResE(sex, start_age, n, t) - Decimal(str(surrender_fact))
return max(roundhu(value, 6),0)
続いて、将来収支の前提条件と、キャッシュフローの計算を置きます。
前回までと少しだけ異なり、性別を入れるようにしています。
# アサンプションの設定 ###################
c_period = 10 # 計算する期間
c_term = 10 # 保険期間
c_sex = "M" # 性別
c_age = 40 # 加入年齢
k = 0.7 # 死亡指数
qwx = [0.02] * len(qx[c_sex]) # 解約率
amount = 1000000 # 保険金額
# 残存表の作成 #################
# 初期生存者数
l0 = 100000
lx = [l0]
dx = []
wx = []
# 生命表の作成
for t in range(c_period):
q = qx[c_sex][c_age + t]
w = qwx[t]
next_d = lx[-1] * q * k
next_w = lx[-1] * w
next_l = lx[-1] - next_d - next_w
lx.append(next_l)
dx.append(next_d)
wx.append(next_w)
# 保険金額の推移
lx_amt = [l * amount for l in lx]
dx_amt = [d * amount for d in dx]
wx_amt = [w * amount for w in wx]
# キャッシュフローの項目
inprem = [] # 保険料収入
benefit = [] # 保険金支払い
surrender = [] # 解約返戻金支払い
expenses = [] # 事業費
netcash = [] # キャッシュフロー結果
P = float(PremE(c_sex, c_age, c_term)) # 保険料をfloat型へ
# キャッシュフローの計算
for t in range(0,c_period):
inprem.append(lx_amt[t] * P) # 保険料の収入
if t == c_term - 1: # 死亡保険金+満期返戻金の支払い
benefit.append((lx_amt[t] - wx_amt[t]))
else: # 死亡保険金の支払い
benefit.append(dx_amt[t])
W = float(SVE(c_sex, c_age, c_term, t + 1))
surrender.append(wx_amt[t] * W) # 解約返戻金の支払い
expenses.append(inprem[t] * 0.1) # 事業費の支払い
# キャッシュフローの計算
netcash.append(inprem[t] - benefit[t] - surrender[t] - expenses[t])
ここまでの結果を確認してみます。
print("t", "inprem", "benefit", "surrender", "expenses","netcash")
for t in range(0, c_period):
print(t, int(inprem[t]/1000000), int(benefit[t]/1000000), \
int(surrender[t]/1000000), int(expenses[t]/1000000), \
int(netcash[t]/1000000))
結果は次のようになります。
0 10755 82 148 1075 9448
1 10531 88 341 1053 9047
2 10311 93 527 1031 8658
3 10094 99 706 1009 8279
4 9882 104 879 988 7909
5 9673 111 1045 967 7548
6 9467 119 1205 946 7195
7 9265 129 1359 926 6850
8 9066 139 1507 906 6513
9 8870 80823 1649 887 -74489
保険料積立金も加えた収支は、
次のようにします。
保険料積立金を性別のある計算式に置き換えています。
# 収支(期末保険料積立金を加える)
reserve =[] # 保険料積立金
inout =[] # 収支の結果
for t in range(0,c_period):
# 期末Vの計算
if t == 0:
# 初年度はV額そのまま
V = float(ResE(c_sex, c_age, c_term, 1))
reserve.append(lx_amt[1] * V)
elif t == c_term - 1:
# 最終年度は全額取り崩し
V = float(ResE(c_sex, c_age, c_term, t))
reserve.append( - lx_amt[t] * V)
else:
# その他はV繰入額を計算
Vt = float(ResE(c_sex, c_age, c_term, t))
Vt1 = float(ResE(c_sex, c_age, c_term, t + 1))
reserve.append(lx_amt[t+1] * Vt1 - lx_amt[t] *Vt)
# 収支の計算
inout.append(netcash[t] - reserve[t])
計算結果を確認すると、次のようになります。
for t in range(0,c_period):
print(t, int(inprem[t]/1000000), int(benefit[t]/1000000), \
int(surrender[t]/1000000), int(expenses[t]/1000000), \
int(reserve[t]/1000000), int(inout[t]/1000000))
0 10755 82 148 1075 9493 -45
1 10531 88 341 1053 9155 -107
2 10311 93 527 1031 8825 -167
3 10094 99 706 1009 8504 -225
4 9882 104 879 988 8192 -282
5 9673 111 1045 967 7886 -337
6 9467 119 1205 946 7586 -390
7 9265 129 1359 926 7293 -443
8 9066 139 1507 906 7007 -494
9 8870 80823 1649 887 -73945 -544
まとめ
今回は、
- ファイル構成の整理
- 共通部分と商品ロジックの分離
- 養老保険を例にした将来収支の確認
を行いました。
数式そのものはこれまでの延長ですが、
コードを整理したことで、
商品を追加するなどの拡張をしやすくすることができます。
今後もpythonの勉強を進めることによって、
拡張できるような内容があれば追加していきます。
📚 ナビゲーション
◀ 前の記事
保険料積立金レート表の作成
▶ 次の記事
複数のCFを合計する
📚 目次
アクチュアリーのためのPython入門