Python
ポエム
TensorFlow
金融

たかしくん (with TensorFlow) と考える積立年金の利率

最近機械学習抜きに TensorFlow を触ったので紹介します。
TensorFlow で方程式の近似解を求めたい人の参考になれば幸いです。

  • (2018/05/07) 平均預け入れ年数を修正

最初に

  • この記事内の人物・会社はフィクションです
  • TensorFlow を使いますが、Deep Learning どころか Neural Network も出てきません
    • あくまで高次方程式の近似解を求めるために使います
  • 定式化のため問題の一部を簡単化してます
  • Google Colaboratory で動かしました(Chrome 以外だと上手く表示されないかも)
  • 本エントリ内の画像は かわいいフリー素材集 いらすとや 様より拝借しております

導入

たかしくんは 現在 26歳 の Software Engineer です。

kaisya_man_bad.png

ある日、とある青い銀行に勤めるお友達(広義)からこんなお誘いがありました。

job_ginkouin.png

「たかしくん!僕と契約して個人積立年金を始めてよ!(=ノルマのための数字になってよ)」

お友達からのお誘いだったので、たかしくんは詳しくお話を聞くことにしました。

聞いてみたところ以下のことが分かりました。

  • 毎月 20,000 円 支払う
    • 今は 1月とし、もし加入したら今月から支払うとする
    • 1年間で 240,000 円支払う
  • 65歳 になるまで支払いを続ける(65 - 26 = 39 年間支払いを続ける)
  • 65歳になったらすぐもらえる(据え置き期間はなし)
  • 9,930,000 円をまとめてもらえる
    • 期間を挟みつつ分割払い、ではない

たかしくんはこれがお得(年利が高い)なら始めてみようと思いました。
ですがその場で年利を計算できなかったため、持ち帰り案件とすることにしました。

shinsyakaijin_run_man2.png

問題の定式化

年利が高いとは(たかしくんが個人積立年金を始める基準)

年利が高いか否かを判断するために、たかしくんは定期預金の年利と比較してみることにしました。

【定期預金の金利を徹底比較!】定期預金金利の高さで選ぶ!おすすめネット銀行ランキング!|ネット銀行比較|ザイ・オンライン

上記のサイトを確認したところ、一番高い銀行では 5年 預けると 0.30% の年利がつくことがわかりました(2018年5月3日時点)。

たかしくんが今から個人積立年金を始めた場合、39年間支払います(上記参照)。
払った年によって預け入れる年数が変わりますが、平均すると (39 + 1) / 2 = 20 年お金を預け入れることになります($ (\sum_{k=1}^N k) / N = (N + 1)/ 2$ より)。

ですので上記の 5年 の定期預金の年利と比較した結果、
たかしくんは 個人積立年金の年利0.35% 以上 なら始めようと決意しました。

年利と総受け取り額の関係

ここで年利と総受け取り額の関係を表すため、下記のようなパラメータを定義します。

パラメータ 内訳
$R$ [%] 個人積立年金の年利
$P$ [円] 毎年たかしくんが支払う金額
$N$ [年] たかしくんが支払いを続ける期間
$S(N)$ [円] たかしくんが $N$ 年間支払った後にもらえる金額

ここで、下記のような $r$ を定義します。

$$
r = 1 + \frac{R}{100}
$$

仮定

ここで少し面倒なのが、年利は 1年間 お金を預けた場合に発生するのに対し、たかしくんは 毎月 積立金を支払っているということです。

例えば、たかしくんが 2018年5月 に支払った $p$ 円は、2019年5月 になって初めて $rp$ 円になるということです。

ここでは計算を簡単にするため、以下の仮定を置きます。
(一ヶ月単位の利率を仮定することでより正確に計算できますが、それは各自でやってみてください)

  • 仮定:たかしくんはその年の最後に $P$ 円をまとめて払ったとして、その 1年後に $r$ 倍になる

1年支払った場合の総受取金額

その年の最後に $P$ 円払ったとして、そのお金に年利がかかる前に返金されるので、下記のようになります。

$$
S(1) = P
$$

2年支払った場合の総受取金額

最初の年に支払った金額には年利がついて、2年目に支払った金額には年利がついてないです。

$$
S(2) = P\cdot r + P
$$

N 年支払った場合の総受取金額

\begin{align}
S(N) &= P \cdot r^{N-1} + P \cdot r^{N-2} + ... + P \cdot r + P\\
&= P \cdot \frac{r^N - 1}{r - 1}
\end{align}

年利を求めるには

ここで実際に求めたい(わかっていない)パラメータは $r$ のみです。
他のパラメータはわかっているので実際に代入してみます。

9930000 = 240000 \cdot \frac{r^{39} - 1}{r - 1}

分かりやすいよう両辺を $240000$ で割ります。

\frac{993}{24} = \frac{r^{39} - 1}{r - 1}

あとは上記の式を満たす $r$ を求めるだけです。

ですがたかしくんは精々2次方程式の解法しか覚えていません。

また、勾配法などでこの方程式の近似解を求めようにも、
たかしくんは微分が大の苦手なので上記の式を $r$ について微分することができません。

困ったことにこのままでは $r$ を求めることができません。

komatta_man2.png

TensorFlow による近似解の計算

しかしたかしくんはただのたかしくんではありません。
闇のパワー(TensorFlow)を持った "たかしくん with TensorFlow" なのです。

kids_chuunibyou_boy.png

そこでたかしくんは TensorFlow を使って利率の近似解を求めることにしました。
(近似解はダメ?厳密解じゃないと許さない?そんなやつは理想を抱いて溺死しろ

コード(TensorFlow)

LEARNING_RATE(学習率)の値によっては収束しなかったり、収束が遅いです。

積立年金.py
import numpy as np
import tensorflow as tf

AGE_START = 26              # 支払い開始年齢
AGE_END = 65                # 支払い終了年齢
YEAR = AGE_END - AGE_START  # 支払い期間
COST_MONTH = 20000          # 月に支払う額
COST_YEAR = COST_MONTH * 12 # 年間支払い額
PENSION_TOTAL = 9930000     # 最終的にもらえる額(発表されてる額)
R_INIT = 2.                 # 年利の初期値(%)
EPOCH = 50                  # エポック数(パラメータの更新回数)
LEARNING_RATE = 0.000001    # 学習率、0.01 とかだとすぐ nan になって収束しないので注意

# Model parameters
r =  tf.Variable([1. + R_INIT/ 100], dtype=tf.float32)

# Model
model = (tf.pow(r, YEAR) - 1) / (r - 1)

# Label
label = tf.constant([PENSION_TOTAL / COST_YEAR], dtype=tf.float32)

# loss
loss = tf.square(model - label)

# optimizer
optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE)
train = optimizer.minimize(loss)

# 初期化用
init = tf.global_variables_initializer()

with tf.Session() as sess:
    init.run()
    print("           init r[%]: ", R_INIT)
    # EPOCH 回パラメータ更新
    for epoch in range(EPOCH):
        sess.run(train)
        # print(sess.run(r))
    r_estimated = (sess.run(r)[0] - 1.) * 100
    pension = sess.run(model)[0] * COST_YEAR
    pension = int(pension)
    print("      estimated r[%]: ", r_estimated)
    print("estimated pension[¥]: ", pension)
    print("             diff[¥]: ", PENSION_TOTAL - pension)
実行結果
           init r[%]:  2.0
      estimated r[%]:  0.3084421157836914
estimated pension[¥]:  9929992
             diff[¥]:  8

上記の結果から、年利は約 $0.308$ % であり、この場合の誤差は $8$ 円であることがわかりました。
993 万円中の 8 円ですので、許しても良いのではないでしょうか。
(許せない人は、コード内の dtype=tf.float32dtype=tf.float64 にしてみましょう)

よって年利が $0.308$ %、すなわち $0.35$ % 未満であることが判明したので、
たかしくんは今回は個人積立年金を 始めない ことにしました。

結論

  • 個人積立年金するぐらいなら定期預金(5年)で十分

最後に

今回の例では色々仮定をおいたり、メリット・デメリットを無視したので、実際はそんなに簡単には決められないかもですが、このような考え方もあると知ってもらえれば幸いです。

ちなみに私は今年の昇給額がしょっぱかったのでまだ始めません。

そしてこれからは Qiita ポエマーとして稼いでいこうと思います。