年齢に対するお年玉の金額を関数で表す
疑問
職場のSlackで「姪にお年玉いくら渡せば良いんだろう」という話になって、そういえば自分も今年秋頃に姪が出来たのでお年玉を渡す必要があると思い出しました。
そこでお年玉の金額はいくらぐらいが適切なのか考え始めました。
世間一般的な回答
世間一般的には「小学生はこれぐらい、中学生はこれぐらい…」としているようです。
しかし私はこれには不満があります。
私は超過累進税率など行政の区分による分け方を常々批判してきました。ここで言う超過累進税率は、所得税などが1,949,000円までは5%で、それから少しだけ稼いだら10%になるという区分による分け方のことです。 No.2260 所得税の税率|国税庁
税金だけではなく障害年金の未成年時から発症してた場合の所得制限などにも同じような不満があります。
累進課税自体はドシドシやるべきだと思いますが、区分による分け方は非常に分かりにくいと常々思っています。
じゃあどうして欲しいのかというと単純に数値を入れて、関数を使って様々な計算をして欲しいと考えています。
区分による分け方と単純な割合による計算は昔ながらの手作業による仕分けをする場合は有用だったと思いますが、今となってはコンピュータで計算が出来るためそこまで問題では無いと考えています。むしろ区分がどちらになるのか気にせずwebなどでサクッと関数を呼び出して分かる方が便利だと思います。
そう考えているので私がそういった計算手段を使うのはダブルスタンダードだと思うのでやめます。
これをお年玉に割り当てると中学生3年生と高校1年生で大きく金額を変えるのは嫌ということです。
よって年齢引数からお年玉の金額を計算する関数を作りたいと思います。
20歳が最後で打ち止めですね。
ちなみにという数式もよく使われるようですね。これで良いかもしれませんが20歳では流石に少なくないかと思ったのと、もうこれ知った時は記事ほぼ書き終わってしまったので関数を作ります。
指数
世間一般的な計算方法を使わないにしても、世間一般的に渡されるお年玉と大きく乖離していると世間体的に問題があると思います。
よってそれにある程度近似するようにしたいと思います。
あまり良さそうな統計が存在せず、総務省が出している統計データの1月の贈与金では自分が全体で出した額しか分かりません。統計局ホームページ/家計調査(家計収支編) 調査結果そして一番知りたい渡す相手の年齢ごとの金額も分かりません。
仕方がないので民間の調査を使うことにします。お年玉の相場を関係性や年齢別に紹介!あげるときのマナーは? | 【楽天市場】 Mama's Life
この調査によるとおおよそ以下の傾向があるそうです。
- 0~6: 1000円
- 7~12: 3000~5000円
- 13~15: 3000~5000円
- 16~18: 5000~10000円
- 19~20: 10000円
これに沿って1つの年齢にごとに対する指数を作ります。
前提として私の収入がそれなりの額で維持されてある程度余裕を持っているということにして多めに設定します。金なくなったら変えます。
また姪というある程度親しい人間に対してのお年玉ということについても考慮の余地があります。知らない人には渡しません。
区分ごとに分けていきましょう。
- 0: 1000
- 6: 3000
- 12: 5000
- 15: 10000
- 18: 20000
- 20: 30000
関数を作ってもらう
自分で数式を作るのは大変苦手なのでこれに近似する関数をChatGPTに作ってもらいます。
なるべくシンプルな関数にしてもらって両替も面倒くさいので端数は切り上げることにしましょう。
単純にプロンプトを作ったらPythonでnumpyとscipyを使ってcurve_fit
を使われて、
3歳の時に-100円になる謎の関数が出来てしまいました。
そもそもぶっ壊れていることと、ずっとこれが同じ結果で実行できるとも思えないので、シンプルに数式を作ってもらいます。
ライブラリを禁止した場合区分を作られてしまったため区分も禁止します。
区分を禁止したところやはり数年間マイナスの金額が発生しまったり、年齢が上がって何故か金額が下がったりということが起きました。仕方がないので指標を増やします。特に幼少期はマイナスにならないように指標を雑に増やして調整します。区分的なことが嫌だから関数を作ってもらっているのに、結局区分のようなことをしてしまっています。つらい。
プログラム言語を使わないで係数を調整するのはやはり困難らしい。最終的な関数が不安定なランタイムに依存しなければ係数を求めることにプログラミング言語を使うことは許容出来るため許可します。
プロンプト
お年玉の金額を計算する関数の数式を作ってください。
指標として年齢に対するお年玉の金額の返り値は以下のようになります。
- 0: 1000
- 3: 2000
- 6: 3000
- 12: 5000
- 15: 10000
- 18: 20000
- 20: 30000
この数値に近似するようにしてください。
なるべくシンプルな数式にしてください。
連続的な数値にしたいので区分分けは禁止します。
両替が面倒なので端数は100円単位で切り上げてください。
係数を計算するためにプログラミング言語などを使っても構いませんが、長く使えるように最終的な数式はプログラミング言語に依存しない汎用的な数式にしてください。
手元で係数をじっくり計算してもあまり意味がなかった
数式らしきものは得られましたがあまり近似しないので手元でPythonをじっくり回して力技で探索回数を増やしましたが、係数はあまり変わりませんでした。
得られた関数
TeX
これを100円単位で切り上げます。
Haskell
module Main where
main :: IO ()
main = mapM_ (\x -> putStrLn $ show x <> ": " <> show (f x)) [0..20]
f :: Int -> Int
f ix = ceiling ((9.43 * x^3 - 162.70 * x^2 + 937.87 * x + 844.51) / 100.0) * 100
where x = fromIntegral ix
100円単位での年齢ごとのお年玉の金額
- 00: 900
- 01: 1700
- 02: 2200
- 03: 2500
- 04: 2600
- 05: 2700
- 06: 2700
- 07: 2700
- 08: 2800
- 09: 3000
- 10: 3400
- 11: 4100
- 12: 5000
- 13: 6300
- 14: 8000
- 15: 10200
- 16: 12900
- 17: 16100
- 18: 20100
- 19: 24700
- 20: 30000
指数と異なるものも結構出てきましたが、曲線を保つためには仕方がないのかな。
やはり1000円単位で四捨五入します
100円単位で妙な端数を入れるのは互いに面倒くさいなと気がついたので1000円単位で四捨五入してもらうことにします。
プロンプト
お年玉の金額を計算する関数の数式を作ってください。
指標として年齢に対するお年玉の金額の返り値は以下のようになります。
- 0: 1000
- 3: 2000
- 6: 3000
- 12: 5000
- 15: 10000
- 18: 20000
- 20: 30000
この数値に近似するようにしてください。
なるべくシンプルな数式にしてください。
連続的な数値にしたいので区分分けは禁止します。
受け渡しが面倒なので1000円単位で四捨五入してください。
係数を計算するためにプログラミング言語などを使っても構いませんが、長く使えるように最終的な数式はプログラミング言語に依存しない汎用的な数式にしてください。
得られた関数
TeX
これを1000円単位で四捨五入します。
Haskell
module Main where
main :: IO ()
main = mapM_ (\x -> putStrLn $ show x <> ": " <> show (f x)) [0..20]
f :: Int -> Int
f ix = round ((269.24 * exp(0.234 * x) + 1196.07) / 1000) * 1000
where x = fromIntegral ix :: Double
1000円単位での年齢ごとのお年玉の金額
- 00: 1000
- 01: 2000
- 02: 2000
- 03: 2000
- 04: 2000
- 05: 2000
- 06: 2000
- 07: 3000
- 08: 3000
- 09: 3000
- 10: 4000
- 11: 5000
- 12: 6000
- 13: 7000
- 14: 8000
- 15: 10000
- 16: 13000
- 17: 16000
- 18: 19000
- 19: 24000
- 20: 30000
グラフ作成
ChatGPTにグラフを作成させるコードを雑に吐き出させます。グラフは冒頭に貼ったやつです。
import matplotlib.pyplot as plt
import numpy as np
from scipy.optimize import curve_fit
# 年齢とお年玉の金額のデータ
ages = np.array([0, 3, 6, 12, 15, 18, 20])
money = np.array([1000, 2000, 3000, 5000, 10000, 20000, 30000])
# 近似する関数の定義 (単純な指数関数を使用)
def money_func(x, a, b, c):
return a * np.exp(b * x) + c
# パラメータのフィッティング
params, covariance = curve_fit(money_func, ages, money)
# フィッティングした関数を使ってお年玉の金額を計算
x_values = np.linspace(0, 20, 100) # 0歳から20歳までの範囲を100点でサンプリング
y_values = money_func(x_values, *params)
# グラフの描画
plt.rcParams['font.family'] = "HackGen Console NF"
plt.figure(figsize=(10, 6))
plt.plot(x_values, y_values, label='Fitted Function', color='blue')
plt.scatter(ages, money, color='red', label='Original Data')
plt.title('年齢に対するお年玉の金額')
plt.xlabel('年齢')
plt.ylabel('お年玉額(円)')
plt.legend()
plt.grid(True)
plt.rc("svg")
plt.savefig("otoshidama-by-age.svg")
感想
20年間のこれぐらいの計算だったら自分でゼロから考えたほうがおそらく楽だった。区分をなるべく作りたくないという謎のこだわりのせいでやたらと面倒になった。
算出過程は割と面白かったですが。