『Python数値計算ノート』ではアフィリエイトプログラムを利用して商品を紹介しています。

生年月日から年齢を計算する

生年月日から年齢を計算する

生年月日と現在の日付を与えて正確な 年齢を計算させるプログラムを作ってみましょう。この手の計算は閏年などが絡んできて案外面倒なのですが、dateutil をインポートすると簡単に実装できます。

# PYTHON_AGE

# In[1]

from datetime import date
from dateutil.relativedelta import relativedelta

datetime は標準ライブラリです。dateutil はサードパーティのライブラリですが、Anaconda には同梱されています。もし dateutil がない場合は pip コマンドでインストールしておいてください。
 
たとえば、1998 年 5 月 12 日から現在までの経過時間を計算する場合は次のようなコードを書きます。

# In[2]

# 生年月日
d0 = date(1998, 5, 12)

# 現在の日付
d1 = date.today()

# 経過時間
dy = relativedelta(d1, d0)

print(dy)
# relativedelta(years=+21, months=+3, days=+8)

この結果は 2019 年 8 月 20 日に実行して得たものです。
コードを実行する日時によって、計算結果が異なります。
 
実行結果にあるように、relativedelta() は日付の差分を何年 (years)、何ヶ月 (months)、何日 (days) という形で返します。
 
relativedelta オブジェクトの years 属性で経過年数 (年齢) を取り出すことができます。

# In[3]

# years属性で経過年数を取得
print(dy.years)
# 21

生年月日と任意の日付を与えて、指定した日付における年齢を計算する関数 age_calculator() を定義してみます。

# In[4]

# 年齢計算関数
def age_calculator(d0, d1=date.today()):
    dy = relativedelta(d1, d0)
    return dy.years

たとえば、2013 年 9 月 15 日生まれの人の、2020 年 1 月 10 日における年齢は次のように計算できます。

# In[5]

# 生年月日
d0 = date(2013, 9, 15)

# 年齢を計算する日付
d1 = date(2030, 1, 10)

# 指定日付における年齢
age = age_calculator(d0, d1)

print(age)
# 16

生年月日をランダムに生成する

rand_birth()

生年月日をランダムに生成する rand_birth() 関数です。

# PYTHON_RANDOM_BIRTH

# In[1]

import numpy as np
from datetime import date
from dateutil.relativedelta import relativedelta

# 生年月日生成関数
def rand_birth(d1=date.today(), upper=100):

    # 現在の年数
    year_now = d1.year

    # 乱数を発生
    rd = np.random.randint(1, upper+1)

    # 現在の年数から乱数を差し引いた日付を
    # 生年月日の初期値とする
    d0 = date(year_now - rd, 1, 1)

    # 追加日数をランダムに決定
    d = np.random.randint(0, 366)

    # 生年月日を決定
    birthday = d0 + relativedelta(days=+d)

    # 年齢を決定
    age = age_calculator(birthday, d1=d1)
    
    return birthday, age

第 1 引数には計算の起点となる日付を渡します (デフォルトは現在の日付)。第 2 引数 upper には年齢上限値を渡します (デフォルトは 100)。戻り値は生年月日と指定した日付における年齢です。
 
年齢上限値を 80 歳として、生年月日と 2015 年 8 月 10 日における年齢を計算する場合は次のように記述します。

# 年齢を計算する日付
d1 = date(2015, 8, 10)

# 生年月日を自動生成
b = rand_birth(d1 = d1, upper=80)

print(b)
# (datetime.date(1958, 8, 10), 56)

乱数を使っているので、実行するたびに結果は異なります。

rand_age()

rand_birth() はどの年齢も等しい確率で生成されますが、日本の年齢別人口分布を反映して年齢を生成しようとすると、かなり高度な統計学の知識を必要とします。ここでは詳細に深入りせずに、結論だけ簡単にまとめておきます。
 
以下の関数を使うと、現実の人口分布に近い確率で年齢を生成できます。
 \[\begin{align*}a_m(x)&=2704x^6-7412x^5+7574x^4-3469x^3+624x^2+79x\\[6pt]a_f(x)&=2168x^6-6090x^5+6426x^4-3078x^3+590x^2+85x\end{align*}\]
$a_m(x),\ a_f(x)$ は、$[0,1]$ の一様乱数 $x$ を使って、それぞれ男性と女性の年齢を決定する関数です。多項式近似とよばれる手法を使って導いた 6 次近似関数に若干の修正を加えています。多項式近似について詳しく学んでみたい人は、当サイトの 機械学習 の記事を参照してください。

このようにして得られた年齢 $y$ の小数部に一年間の平均日数 365.2425 日を掛けて、日数 $d$ に変換します。
 \[d=365.2425(y-[y])\]
ここで $[y]$ は $y$ の整数部であり、$y-[y]$ は $y$ の小数部だけを取り出すことを意味します。指定した日付から年数 $y$ と日数 $d$ を差し引けば生年月日を取得できます。

# PYTHON_AGE_03

import numpy as np
from datetime import date
from dateutil.relativedelta import relativedelta

# 年齢関数
def rand_age(sex="m", d1=date.today()):

    # 0以上1未満の乱数を生成
    x = np.random.rand()

    # 累積確率分布近似曲線を使って年齢を決定
    if sex == "m":
        y =   2704 * x**6 - 7412 * x**5 + 7574 * x**4\
            - 3469 * x**3 +  624 * x**2 +   79 * x

    elif sex == "f":
        y =   2168 * x**6 - 6090 * x**5 + 6426 * x**4\
            - 3078 * x**3 +  590 * x**2 +   85 * x

    # 年齢の端数を日数に変換
    d = 365.2425 * (y - int(y))

    # 年齢を年数と日数で表す
    age = relativedelta(years = +int(y), days = +int(d))

    # 生年月日を算出
    birth = d1 - age

    return birth, age.years

rand_age() で女性の年齢と生年月日をランダム生成してみます。

np.random.seed(10)

# 生年月日と年齢をランダムに生成
birth, age = rand_age("f")

print(birth)
print(age)

# 1947-03-05
# 72

コメント

  1. あとりえこばと より:

    ChatGPT と Bard に生年月日と現在の日付に基づいて年齢を計算するアルゴリズムについて尋ねてみました。

    [ChatGPT] 生年月日と現在の日付から年齢を計算する一般的なアルゴリズムは次の通りです。
    1.生年月日から現在の年齢に影響する要素を抽出します。これは、生年月日から年、月、日を取得することです。
    2.現在の年月日から、生年月日に関する情報を取得します。これも現在の年、月、日を取得することです。
    3.年齢を計算するために、現在の年から生年を引きます。ただし、誕生月日がまだ来ていない場合は、年齢を1つ引きます。
    4.誕生月日がまだ来ていないかどうかを判定するために、現在の月と生年月日の月を比較します。現在の月が生年月日の月よりも前の場合、年齢を1つ引きます。
    5.誕生月日がまだ来ていないかどうかを判定するために、現在の月と生年月日の月が同じ場合、現在の日と生年月日の日を比較します。現在の日が生年月日の日よりも前の場合、年齢を1つ引きます。
    このアルゴリズムに基づいて、生年月日と現在の日付から年齢を計算する関数を実装することができます。先程の回答でも示したコードはこのアルゴリズムに基づいています。

    [Bard] はい、生年月日と現在の日付を受け取って、年齢を計算する一般的なアルゴリズムは次のとおりです。
    1.現在の日付を取得します。
    2.生年月日を取得します。
    3.現在の日付から生年月日を引いて、年数を取得します。
    4.年数に 1 を加算して、年齢を取得します。
    たとえば、生年月日が 1990-01-01 で現在の日付が 2023-05-15 の場合、年齢は 33 になります。このアルゴリズムにはいくつかの注意点があります。このアルゴリズムは、うるう年を考慮していません。うるう年を考慮する場合は、現在の年がうるう年かどうかを確認してから、年数に 1 を加算する必要があります。このアルゴリズムは、誕生日にまだ達していない場合の人を考慮していません。誕生日にまだ達していない場合、年数から 1 を引く必要があります。お役に立てれば幸いです。