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入門(商品の追加)

0
Last updated at Posted at 2026-10-24

アクチュアリーのためのPython入門(アクチュアリーPython活用編第1回)

商品の追加

📚 アクチュアリーのためのPython入門
この記事はアクチュアリーPython活用編の一部です。
▶ 目次はこちら
▶ 逆引きガイドはこちら

はじめに

入門編や他の応用編では、分かりやすさや
私自身が使っているExcelVBAからの移行しやすさを重視して
コードを考えてきました。

このPython活用編では、実務を考慮して、
もっと大きなデータを扱う上ことを考えて、
もう少しだけ効率化を行ってい行きます。

今回は、今扱っている保険種類を増やし、
基礎率や給付の異なる保険種類を増やして複雑化させていきます。

個人年金

簡単な確定年金を追加してみます。
保険料払込中に死亡した場合は既払込保険料相当額を支払います。
保険料を払い終えると、10年の確定年金が支払われます。

営業保険料の計算式は次になります。

計算基礎は次のとおりです。

  • 保険料計算基礎
    予定死亡率は標準生命表の1.5σ水準、予定利率は1%
  • 責任準備金計算基礎
    予定死亡率は標準生命表、予定利率は0.25%

なお、標準生命表の1.5σ水準の死亡率を作成した記事はこちらです。

医療保険

入院のみの給付ですが、医療保険を加えてみます。
定期医療保険で、災害または疾病で入院したときのみ給付で
限度日数は60日の設定です。

計算基礎は次のとおりです。

  • 保険料計算基礎
    予定死亡率は標準生命表の第三分野用、予定利率は0.6%
  • 責任準備金計算基礎
    予定死亡率は標準生命表の第三分野用、予定利率は0.25%

計算基数表の修正

異なる計算基礎を考慮した基数表base_b.pyに、
年金の保険料計算基礎および責任準備金計算基礎、
医療保険の保険料計算基礎および責任準備金計算基礎が加わりますので、
大きく修正を行います。

なお、base_b.pyを作成したときの記事はこちらです。

ここでは、予定入院率lamb、平均入院日数をstayとします。
なお、予定入院率、平均入院日数は適当に作成したもので、
どこかの基礎率を引用してきたわけではありません。

年金と医療保険を追加するために必要な
基礎率や計算基数、給付現価を加えています。

base_b.py
+ import numpy as np
# 責任準備金計算基礎を含む
# 年齢の範囲
ages = list(range(0, 114))

# 死亡率(標準生命表2018)
# 男性
qx2M = [0.00081,0.00056,0.00036,0.00022,0.00014,0.0001,0.00009,0.00009,0.00009,0.00009,
      0.0001,0.0001,0.00011,0.00013,0.00017,0.00023,0.0003,0.00038,0.00046,0.00053,
      0.00059,0.00063,0.00066,0.00068,0.00068,0.00067,0.00065,0.00064,0.00064,0.00066,
      0.00068,0.00069,0.0007,0.00072,0.00074,0.00077,0.00083,0.0009,0.00099,0.00109,
      0.00118,0.00129,0.0014,0.00151,0.00163,0.00177,0.00194,0.00214,0.00236,0.00259,
      0.00285,0.00311,0.00337,0.00364,0.00391,0.00422,0.00458,0.005,0.00546,0.00597,
      0.00653,0.00716,0.00785,0.00858,0.00935,0.01015,0.011,0.0119,0.01292,0.01408,
      0.01544,0.01702,0.01886,0.02099,0.02346,0.02637,0.02978,0.03381,0.03853,0.04396,
      0.05006,0.05673,0.06402,0.07235,0.08177,0.09175,0.10269,0.11466,0.12775,0.14204,
      0.1576,0.17453,0.1929,0.21279,0.23426,0.25739,0.28222,0.30878,0.33708,0.3671,
      0.39881,0.4321,0.46686,0.50292,0.54006,0.578,0.61642,0.65494,0.69314,1]
# 女性
qx2F = [0.00078,0.00053,0.00033,0.00019,0.00011,0.00008,0.00008,0.00008,0.00007,0.00007,
      0.00007,0.00007,0.00008,0.0001,0.00012,0.00014,0.00016,0.00019,0.00021,0.00023,
      0.00025,0.00026,0.00027,0.00028,0.00029,0.00029,0.0003,0.00031,0.00032,0.00034,
      0.00037,0.0004,0.00044,0.00049,0.00054,0.00059,0.00065,0.00071,0.00077,0.00083,
      0.00088,0.00093,0.00099,0.00104,0.00112,0.00122,0.00135,0.0015,0.00167,0.00182,
      0.00197,0.00211,0.00225,0.00241,0.00256,0.0027,0.00284,0.003,0.00317,0.00338,
      0.00363,0.00389,0.00414,0.00436,0.00458,0.00484,0.00515,0.00554,0.00603,0.00661,
      0.0073,0.00814,0.00912,0.01026,0.01152,0.01289,0.01443,0.01623,0.0184,0.02101,
      0.02414,0.02778,0.03195,0.03659,0.04249,0.04885,0.05596,0.0639,0.07275,0.08261,
      0.09357,0.10576,0.11928,0.13424,0.15078,0.16901,0.18906,0.21104,0.23506,0.26122,
      0.28959,0.32021,0.3531,0.3882,0.42543,0.46462,0.50554,0.54785,0.59115,0.63494,
      0.67863,0.72158,0.76308,1]

# 死亡率(標準生命表2018の1.5σ)
# 男性
qx15M = [
    0.00078,0.00054,0.00035,0.00021,0.00013,0.0001,0.00009,0.00009,0.00009,0.00009,
    0.00009,0.0001,0.00011,0.00013,0.00016,0.00022,0.00029,0.00037,0.00045,0.00051,
    0.00057,0.00061,0.00064,0.00066,0.00066,0.00065,0.00063,0.00062,0.00062,0.00064,
    0.00065,0.00066,0.00067,0.00069,0.00071,0.00074,0.0008,0.00087,0.00095,0.00104,
    0.00114,0.00124,0.00135,0.00146,0.00157,0.0017,0.00185,0.00203,0.00223,0.00245,
    0.0027,0.00294,0.0032,0.00345,0.00372,0.00402,0.00437,0.00477,0.00521,0.0057,
    0.00625,0.00685,0.00751,0.00822,0.00896,0.00973,0.01054,0.01141,0.01238,0.0135,
    0.01479,0.01631,0.01808,0.02012,0.0225,0.02529,0.02857,0.03245,0.03698,0.04221,
    0.04807,0.05447,0.06146,0.06945,0.07853,0.08807,0.09849,0.10986,0.12226,0.13575,
    0.15041,0.16632,0.18354,0.20215,0.22221,0.24378,0.26691,0.29164,0.31799,0.34595,
    0.3755,0.4066,0.43915,0.47303,0.50807,0.54408,0.5808,0.61793,0.65512,0.69202,
    1
]
# 女性
qx15F = [
    0.00075,0.00051,0.00032,0.00018,0.00011,0.00008,0.00008,0.00008,0.00007,0.00007,
    0.00006,0.00007,0.00008,0.00009,0.00011,0.00014,0.00016,0.00019,0.00021,0.00023,
    0.00024,0.00025,0.00026,0.00027,0.00028,0.00028,0.00029,0.0003,0.00031,0.00033,
    0.00035,0.00039,0.00043,0.00047,0.00052,0.00057,0.00063,0.00068,0.00074,0.0008,
    0.00085,0.0009,0.00095,0.001,0.00107,0.00117,0.0013,0.00145,0.00161,0.00176,
    0.0019,0.00203,0.00216,0.00229,0.00243,0.00255,0.00268,0.00282,0.00299,0.00319,
    0.00343,0.00367,0.00391,0.00412,0.00433,0.00457,0.00487,0.00524,0.0057,0.00625,
    0.00691,0.00771,0.00865,0.00973,0.01093,0.01224,0.01371,0.01544,0.01751,0.02002,
    0.02301,0.0265,0.0305,0.03495,0.04064,0.04675,0.05357,0.06117,0.06963,0.07905,
    0.08951,0.10112,0.11399,0.12822,0.14393,0.16124,0.18027,0.20112,0.22392,0.24875,
    0.27569,0.3048,0.3361,0.36959,0.40519,0.44279,0.48219,0.52313,0.56528,0.60819,
    0.65135,0.6942,0.73607,1
]

+ # 死亡率(標準生命表2018医療用)
+ # 男性
+ qxHM = [
+    0.00053,0.00022,0.00015,0.00011,0.00008,0.00006,0.00006,0.00006,0.00005,0.00005,
+    0.00005,0.00006,0.00006,0.00008,0.00009,0.00011,0.00015,0.00018,0.00022,0.00027,
+    0.00031,0.00034,0.00036,0.00039,0.00039,0.00039,0.00039,0.00039,0.0004,0.00041,
+    0.00041,0.00043,0.00044,0.00046,0.00048,0.00051,0.00054,0.00059,0.00064,0.00071,
+    0.00076,0.00084,0.00091,0.00099,0.00109,0.00118,0.0013,0.00142,0.00158,0.00173,
+    0.00191,0.00212,0.00236,0.00263,0.00294,0.00327,0.00364,0.00403,0.00445,0.00491,
+    0.00548,0.00606,0.0066,0.00715,0.00776,0.00845,0.00922,0.01007,0.01094,0.01192,
+    0.01308,0.01443,0.01594,0.01773,0.0199,0.02242,0.02527,0.02848,0.03212,0.03614,
+    0.04046,0.04511,0.05041,0.05663,0.0636,0.0711,0.07868,0.08667,0.09545,0.10539,
+    0.11657,0.12767,0.13949,0.15204,0.16536,0.17945,0.19434,0.21005,0.22656,0.24387,
+    0.26198,0.28086,0.30047,0.32077,0.34171,0.3632,0.38516,0.40749,0.43007,0.45275,
+    0.47541,0.49788,0.51998,0.54156,0.56243,0.58241,1
+ ]
+ # 女性
+ qxHF = [
+    0.00052,0.0002,0.00014,0.00009,0.00007,0.00006,0.00005,0.00005,0.00004,0.00004,
+    0.00004,0.00004,0.00004,0.00005,0.00006,0.00008,0.00008,0.0001,0.00012,0.00013,
+    0.00015,0.00015,0.00016,0.00016,0.00016,0.00016,0.00017,0.00018,0.00019,0.00021,
+    0.00022,0.00023,0.00025,0.00026,0.00027,0.00029,0.00032,0.00034,0.00038,0.00041,
+    0.00043,0.00047,0.0005,0.00056,0.00062,0.00067,0.00071,0.00076,0.00085,0.00094,
+    0.00102,0.0011,0.00118,0.00125,0.00134,0.00145,0.00156,0.00167,0.00179,0.00193,
+    0.00209,0.00228,0.00249,0.00273,0.00294,0.00317,0.00345,0.00378,0.00414,0.00456,
+    0.0051,0.00576,0.00653,0.00744,0.0085,0.00967,0.01101,0.01257,0.01442,0.01656,
+    0.01899,0.02176,0.02498,0.02883,0.03324,0.03843,0.04426,0.05097,0.05847,0.06672,
+    0.07574,0.08566,0.09665,0.10906,0.1227,0.13693,0.15156,0.16698,0.18319,0.2002,
+    0.218,0.23658,0.25592,0.276,0.29676,0.31817,0.34015,0.36264,0.38554,0.40874,
+    0.43214,0.4556,0.47897,0.50212,0.52487,0.54707,0.56856,0.58917,1
+ ]
+ # 入院率(87歳まで)
+ # 男性
+ lambM = [
+    0.49235,0.32661,0.19285,0.08821,0.03796,0.02736,0.04827,0.0587,0.06715,0.06563,
+    0.05795,0.04783,0.03909,0.03491,0.03489,0.03762,0.04164,0.04554,0.0482,0.04957,
+    0.04987,0.0493,0.04806,0.04636,0.04443,0.04252,0.04089,0.0398,0.03943,0.03969,
+    0.04042,0.04144,0.04259,0.04373,0.04486,0.04598,0.04711,0.04825,0.04945,0.05073,
+    0.05218,0.05384,0.05578,0.05805,0.06063,0.0635,0.06666,0.07007,0.07375,0.07774,
+    0.08213,0.08699,0.0924,0.09841,0.105,0.1121,0.11968,0.12767,0.13604,0.14479,
+    0.15391,0.16342,0.17331,0.18361,0.19442,0.20584,0.218,0.23099,0.24488,0.25951,
+    0.27467,0.29015,0.30574,0.3213,0.33683,0.35242,0.36812,0.384,0.4001,0.41634,
+    0.43261,0.44883,0.46487,0.48066,0.49623,0.51163,0.52691,0.54211
+ ]
+ # 女性
+ lambF = [
+    0.42053,0.27498,0.15773,0.06592,0.02172,0.01314,0.03046,0.04421,0.05243,0.0515,
+    0.04497,0.03627,0.02895,0.026,0.02709,0.03088,0.03597,0.04107,0.04524,0.04882,
+    0.05243,0.05668,0.06216,0.06928,0.07777,0.08721,0.0972,0.10733,0.11716,0.12603,
+    0.13321,0.13799,0.13965,0.13773,0.13285,0.12585,0.11762,0.10902,0.10082,0.09329,
+    0.08661,0.08093,0.07641,0.07318,0.07114,0.07014,0.07003,0.07065,0.07187,0.07359,
+    0.07577,0.07833,0.08122,0.08439,0.08782,0.0915,0.09544,0.09964,0.10408,0.10881,
+    0.11384,0.11921,0.12495,0.13108,0.13767,0.14477,0.15244,0.16073,0.16975,0.17971,
+    0.19088,0.20352,0.21789,0.23413,0.25193,0.27088,0.29055,0.31055,0.33078,0.35245,
+    0.37702,0.40596,0.4407,0.48215,0.52922,0.58038,0.63409,0.68882
+ ]
+ # 平均入院日数
+ # 男性
+ stayM = [
+    8.28,6.43,4.93,3.74,3.13,2.96,4.14,3.51,4.05,4.68,
+    5.34,5.98,6.57,7.05,7.43,7.69,7.83,7.86,7.78,7.67,
+    7.64,7.73,7.82,7.91,8,8.09,8.19,8.29,8.37,8.47,
+    8.58,8.67,8.77,8.86,8.97,9.07,9.17,9.28,9.38,9.48,
+    9.59,9.69,9.8,9.92,10.02,10.13,10.25,10.35,10.47,10.59,
+    10.7,10.81,10.92,11.05,11.17,11.28,11.4,11.53,11.64,11.77,
+    11.9,12.02,12.14,12.27,12.39,12.53,12.65,12.78,12.91,13.04,
+    13.18,13.31,13.44,13.58,13.71,13.85,13.99,14.12,14.26,14.4,
+    14.54,14.68,14.81,14.96,15.11,15.24,15.39,15.53
+ ]
+ # 女性
+ stayF = [
+    8.03,6.44,5.14,4.1,3.53,3.37,4.73,4.02,4.74,5.61,
+    6.54,7.42,8.16,8.68,9.01,9.17,9.2,9.12,8.97,8.77,
+    8.53,8.28,8.03,7.79,7.58,7.41,7.28,7.2,7.17,7.18,
+    7.21,7.24,7.24,7.21,7.17,7.13,7.13,7.2,7.34,7.5,
+    7.66,7.82,7.98,8.14,8.31,8.48,8.65,8.83,9.01,9.19,
+    9.37,9.55,9.74,9.94,10.13,10.33,10.53,10.73,10.94,11.15,
+    11.36,11.57,11.78,12.01,12.23,12.45,12.68,12.9,13.14,13.37,
+    13.61,13.85,14.08,14.33,14.57,14.82,15.07,15.32,15.57,15.83,
+    16.08,16.34,16.6,16.87,17.13,17.4,17.66,17.93
+ ]
# 死亡率(P基礎、V基礎)
qx = {"P":{"M":qx15M, "F":qx15F}, "V":{"M":qx2M, "F":qx2F}, \
+        "AnnP":{"M":qx15M, "F":qx15F}, "AnnV":{"M":qx2M, "F":qx2F}, \
+        "HosP":{"M":qxHM, "F":qxHF}, "HosV":{"M":qxHM, "F":qxHF}
    }
# 予定利率(P基礎、V基礎)
ival = {"P":0.006, "V":0.0025, \
+ "AnnP":0.01, "AnnV":0.0025, "HosP":0.006, "HosV":0.0025
    }
# 最終年齢
def omega(base, sex):
    return len(qx[base][sex])
+ # 入院率
+ lamb = {"M":lambM, "F":lambF}
+ # 平均入院日数
+ stay = {"M":stayM, "F":stayF}

# 基数表の作成(死亡保険用)
# 辞書の作成
Dx = {}
Cx = {}
Nx = {}
Mx = {}
+ Sx = {}
+ Rx = {}

# 計算基数表の作成(P:死亡保険P基礎、V:死亡保険V基礎、AnnP:年金P基礎、AnnV:年金V基礎)
- for base in ("P", "V"):
+ for base in ("P", "V", "AnnP", "AnnV"):

    # baseごとの辞書を初期化
    Dx[base] = {}
    Cx[base] = {}
    Nx[base] = {}
    Mx[base] = {}
+    Sx[base] = {}
+    Rx[base] = {}

    for sex in ("M","F"):

        # 初期生存者数
        l0 = 100000

        # lx, dx
        lx = [l0]
        dx = []

        # 生命表の作成
        for q in qx[base][sex]:
            next_d = lx[-1] * q
            next_l = lx[-1] - next_d
            lx.append(next_l)
            dx.append(next_d)

        # 利率と現価率
        i = ival[base]
        v = 1 / (1 + i)

        # Dx, Cx
        Dx[base][sex] = []
        Cx[base][sex] = []

        for age, l, d in zip(ages, lx, dx):
            Dx[base][sex].append(l * v ** age)
            Cx[base][sex].append(d * v ** (age + 0.5))  # 即時払(年央近似)

        # Nx, Mx
        Nx[base][sex] = []
        Mx[base][sex] = []

        Dx_sum = 0
        Cx_sum = 0

        for D, C in zip(reversed(Dx[base][sex]), reversed(Cx[base][sex])):
            Dx_sum += D
            Cx_sum += C
            Nx[base][sex].append(Dx_sum)
            Mx[base][sex].append(Cx_sum)

        Nx[base][sex] = list(reversed(Nx[base][sex]))
        Mx[base][sex] = list(reversed(Mx[base][sex]))

+        # Sx, Rx
+        Sx[base][sex] = []
+        Rx[base][sex] = []
+
+        Nx_sum = 0
+        Mx_sum = 0
+
+        for N, M in zip(reversed(Nx[base][sex]), reversed(Mx[base][sex])):
+            Nx_sum += N
+            Mx_sum += M
+            Sx[base][sex].append(Nx_sum)
+            Rx[base][sex].append(Mx_sum)
+
+        Sx[base][sex] = list(reversed(Sx[base][sex]))
+        Rx[base][sex] = list(reversed(Rx[base][sex]))
+
+ # 基数表の作成(医療保険用)
+ # 辞書の作成
+ Hx = {}
+ Ix = {}
+
+ for base in ("HosP", "HosV"):
+    # baseごとの辞書を初期化
+    Dx[base] = {}
+    Cx[base] = {}
+    Hx[base] = {}
+    Nx[base] = {}
+    Mx[base] = {}
+    Ix[base] = {}
+
+    for sex in ("M","F"):
+
+        # 初期生存者数
+        l0 = 100000
+
+        # lx, dx
+        lx = [l0]
+        dx = []     # 死亡者数
+        hx = []     # 入院者数
+
+        # 生命表の作成
+        for q, h in zip(qx[base][sex], lamb[sex]):
+            qd = q * (1-h/2)    # 死亡率
+            hp = h * (1-q/2)    # 入院率
+            next_d = lx[-1] * qd
+            next_h = lx[-1] * hp
+            next_l = lx[-1] - next_d
+            lx.append(next_l)
+            dx.append(next_d)
+            hx.append(next_h)
+
+        # 利率と現価率
+        i = ival[base]
+        v = 1 / (1 + i)
+
+        # Dx, Cx
+        Dx[base][sex] = []
+        Cx[base][sex] = []
+        Hx[base][sex] = []
+
+        for age, l, d, h, T in zip(ages, lx, dx, hx, stay[sex]):
+            Dx[base][sex].append(l * v ** age)
+            Cx[base][sex].append(d * v ** (age + 0.5))  # 即時払(年央近似)
+            Hx[base][sex].append(h * T * v ** (age + 0.5))  # 即時払(年央近似)
+
+        # Nx, Mx
+        Nx[base][sex] = []
+        Mx[base][sex] = []
+        Ix[base][sex] = []
+
+        Dx_sum = 0
+        Cx_sum = 0
+        Ix_sum = 0
+
+        for D, C, H in zip(reversed(Dx[base][sex]), reversed(Cx[base][sex]), reversed(Hx[base][sex])):
+            Dx_sum += D
+            Cx_sum += C
+            Ix_sum += H
+            Nx[base][sex].append(Dx_sum)
+            Mx[base][sex].append(Cx_sum)
+            Ix[base][sex].append(Ix_sum)
+
+        Nx[base][sex] = list(reversed(Nx[base][sex]))
+        Mx[base][sex] = list(reversed(Mx[base][sex]))
+        Ix[base][sex] = list(reversed(Ix[base][sex]))
+
# 死亡給付現価
def A1xn(base, sex, start_age, n):
    return (Mx[base][sex][start_age] - Mx[base][sex][start_age + n]) / Dx[base][sex][start_age]

# 養老給付現価
def Axn(base, sex, start_age, n):
    return (Mx[base][sex][start_age] - Mx[base][sex][start_age + n] + Dx[base][sex][start_age + n]) / Dx[base][sex][start_age]

# 終身給付現価
def A1x(base, sex, start_age):
    return Mx[base][sex][start_age]/Dx[base][sex][start_age]

# 定期年金現価(期始年払)
def axn(base, sex, start_age, n):
    return (Nx[base][sex][start_age] - Nx[base][sex][start_age + n]) / Dx[base][sex][start_age]

# 定期年金現価(期始月払)
def axn12(base, sex, start_age, n):
    a = (Nx[base][sex][start_age] - Nx[base][sex][start_age + n]) / Dx[base][sex][start_age]
    a12 = a - 11/24 * (1 - Dx[base][sex][start_age + n] / Dx[base][sex][start_age])
    return a12

# 終身年金現価(期始払)
def ax(base, sex, start_age):
    return Nx[base][sex][start_age] / Dx[base][sex][start_age]

+ # 生存給付現価
+ def Axn1(base, sex, start_age, n):
+     return Dx[base][sex][start_age + n] / Dx[base][sex][start_age]
+
+ # 累加定期給付現価
+ def IA1xn(base, sex, start_age, n):
+     return (Rx[base][sex][start_age] - Rx[base][sex][start_age + n] - n * Mx[base][sex][start_age + n]) / Dx[base][sex][start_age]
+ 
+ # 確定年金現価
+ def annuity_certain(base, n):
+     v = 1 / (1 + ival[base])
+     return (1 - v ** n) / (1 - v)
+
+ # 入院給付現価 追加
+ def A1xnH(base, sex, start_age, n):
+     return (Ix[base][sex][start_age] - Ix[base][sex][start_age + n]) / Dx[base][sex][start_age]

# 保険期間の変換
def parse_term(period, age):
    # 数値の場合はそのまま保険期間
-    if isinstance(period, int):
+    if isinstance(period, (int, np.integer)): # ←isinstanceは整数かどうかの判定
        return period

    # CSVから読み込んだ""文字列
    if isinstance(period, str):
        period = period.strip()      # 前後の空白を除去

        # 数字ならそのまま
        if period.isdigit():
            return int(period)

        # 文字列かつAではじまる場合は保険期間=満期年齢-加入年齢
        # startswithはAではじまっているかの判定
        if period.upper().startswith("A"): 
            maturity_age = int(period[1:])
            term = maturity_age - age
            # 保険期間が0以下ならエラー
            if term <= 0:
                raise ValueError("満期年齢が加入年齢以下です")
            return term

    raise ValueError(f"不正な期間指定: {period}")  

# decimal のインポート
from decimal import Decimal, ROUND_HALF_UP, getcontext

# 四捨五入
def roundhu(value, ndigits):
    getcontext().prec = 28
    d = Decimal(str(value))
    quant = Decimal("1").scaleb(-ndigits)
    return d.quantize(quant, rounding=ROUND_HALF_UP)

年齢満期を年満期に変換するparse_termは、
CSVファイルやExcelファイルからデータを読み込んだ場合に
エラーとなる可能性があるので、回避するために条件を加えています。

保険料と保険料積立金の計算

続いて、年金の保険料と保険料積立金を計算するファイルを
annuity.pyとして作成します。
他の商品と比較して特に難しい部分はありません。

annuity.py
# 年金
from core_b import *

# 予定事業費
alpha = 0.05
delta = 0.05
gamma = 0.005
beta = 0.03

# 営業保険料
def PremA(sex, start_age, term):
    n = parse_term(term, start_age)
    # 営業保険料の計算
    an = axn("AnnP", sex, start_age, n)
    value = ((1 + gamma) * Axn1("AnnP", sex, start_age, n) * annuity_certain("AnnP", 10) \
             + alpha + gamma * an) / ((1 - beta - delta) * an - IA1xn("AnnP", sex, start_age, n))
    # 端数処理
    value = roundhu(value, 6)
    return value

# 純保険料
def netPremA(base, sex, start_age, term):
    n = parse_term(term, start_age)
    p = float(PremA(sex, start_age, n))    
    value = ((1 + gamma) * Axn1("AnnP", sex, start_age, n) * annuity_certain(base, 10) \
             + p * IA1xn(base, sex, start_age, n)) / axn(base, sex, start_age, n)
    return value

# 保険料積立金
def ResA(base, sex, start_age, term, t):
    n = parse_term(term, start_age)
    # 払込中
    if t < n:
        p = float(PremA(sex, start_age, n))
        benefit = (1 + gamma) * Axn1("AnnP", sex, start_age + t, n - t) * annuity_certain(base, 10) \
            + p * (IA1xn(base, sex, start_age + t, n -t) + t * A1xn(base, sex, start_age + t, n - t))
        income = netPremA(base, sex, start_age, n) * axn(base, sex, start_age + t, n - t)
        value = Decimal(str(benefit)) - Decimal(str(income))
    # 払込後
    else:
        value = Decimal(str((1 + gamma) * annuity_certain(base, n + 10 - t)))
    # 平準純保険料式
    Vn = roundhu(value, 6)
    # 5年チルメル式
    if t < 5:
        a = alpha * axn(base, sex, start_age + t, 5 - t) / axn(base, sex, start_age, 5)
    else:
        a = 0
    value = roundhu(value - Decimal(str(a)), 6)
    Vz = max(value, 0)
    # 解約返戻金
    if t < 10:
        surrender_fact = alpha * (1 - t / min(n, 10))
    else:
        surrender_fact = 0
    value = roundhu(Vn - Decimal(str(surrender_fact)), 6)
    W = max(value, 0)
    return Vn, Vz, W

続いて、医療保険です。こちらはhospital.pyとして作成します。

hospital.py
# 年金
from core_b import *

# 予定事業費
alpha = 2
delta = 0.07
gamma = 0.215
beta = 0.03

# 営業保険料
def PremH(sex, start_age, term):
    n = parse_term(term, start_age)
    # 営業保険料の計算
    an = axn("HosP", sex, start_age, n)
    value = (A1xnH("HosP", sex, start_age, n) + alpha + gamma * an) / ((1 - beta - delta) * an)
    # 端数処理
    value = roundhu(value, 6)
    return value

# 純保険料
def netPremH(base, sex, start_age, term):
    n = parse_term(term, start_age)
    value = A1xnH(base, sex, start_age, n) / axn(base, sex, start_age, n)
    return value

# 保険料積立金
def ResH(base, sex, start_age, term, t):
    n = parse_term(term, start_age)
    benefit = Decimal(str(A1xnH(base, sex, start_age + t, n - t)))
    income = netPremH(base, sex, start_age, n) * axn(base, sex, start_age + t, n - t)
    value = Decimal(str(benefit)) - Decimal(str(income))
    # 平準純保険料式
    Vn = roundhu(value, 6)
    # 5年チルメル式
    if t < 5:
        a = alpha * axn(base, sex, start_age + t, 5 - t) / axn(base, sex, start_age, 5)
    else:
        a = 0
    value = roundhu(value - Decimal(str(a)), 6)
    Vz = max(value, 0)
    # 解約返戻金
    if t < 10:
        surrender_fact = alpha * (1 - t / min(n, 10))
    else:
        surrender_fact = 0
    value = roundhu(Vn - Decimal(str(surrender_fact)), 6)
    W = max(value, 0)
    return Vn, Vz, W

まとめ

とりあえず、今回はここまでとします。
これからの準備として、計算基礎が異なる商品を追加しました。
次回以降、こららを合わせて、少し大きめのサンプルデータを扱った場合に、
どんな工夫ができるのか考えていきたいと思います。


📚 ナビゲーション

▶ 次の記事

📚 目次
アクチュアリーのための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?