Up

情報量基準AICBICのシミュレーション

 

モデルのパラメータ数を増やしていくと真のモデルとの誤差が増加することがBrunton and Kutz (2019)に説明されている。オーバーフィッティングのために適用モデルが真のモデルから離れていくことをこのウェブサイトにおけるシミュレーションで示した。適用モデルの選択に用いる指標としてBrunton and Kutz (2019)では情報量基準AICBICについて説明されている。AICBICについて、Brunton and Kutz (2019)のシミュレーション例であるCode 4.14の設定でシミュレーションを行ってみた。

 

Code 4.14では、真のモデルは次式で与えられる2次の多項式である。

データは真のモデルに標準偏差0.1の正規分布に従うノイズの加えられたものである。

データの観測点は、区間において一様に分布するように設定される。

分析に用いられるモデルは、次多項式である。

情報量基準AICおよびBICは、モデルの推定が最尤法で行われたとき、次式で与えられる(Konishi and Kitagawa, 2008)

最尤法を適用する確率モデルは、観測点における観測値がであるとき、次式で設定する。

このとき、多項式の最尤推定値は次式

の最小2乗法による解で与えられる。すなわち、

である(cf. 岡本、2009p. 26)。このときの誤差をとおくとき、の最尤推定値は次式で与えられる。

 

シミュレーションプログラムを2本書いてみた。

(1)サンプルサイズn_pnts=100のデータが与えられたときのAICおよびBICの振る舞いを調べた。

(2)データのサンプルサイズをn_pnts=20, 100, 1000と大きくしたときのAICおよびBICの振る舞いを調べた。

 

 

(1)サンプルサイズn_pnts=100のときのAICおよびBIC

 

サンプルスクリプトをリスト1のように用意した。

リスト1のスクリプトをPython 3.11.8/Anacondaで実行すると、まずサンプルサイズn_pnts=100の条件において、n=1000回のシミュレーションの結果が図示される。各シミュレーションにおいて、0次から5次までの多項式モデルが適用され、AICBICが算出された。0次から5次までの多項式モデルのAICBICの各1000回のシミュレーションにおける値のボックスプロットと平均値を図1の左側のグラフに示す。2次多項式から5次多項式モデルのグラフは右側のグラフに示した。

 

図1

 

0次多項式から2次多項式までAICおよびBICは急激に減少しているが、2次以上の多項式では変化はわずかな増加が認められる。2次以上の多項式モデルでは、ボックスプロットで示される分布の重なりがある。AICあるいはBICで常に正しいモデルが選択できるようではなさそうである。

情報量基準AICおよびBICで正しい選択がどの程度できるか、その頻度を調べた。1000回のシミュレーションにおいて、AICおよびBICにより正しいモデルとして選択された度数を各次数の多項式モデルごとに数え、ヒストグラムで表した(図2)。

図2

 

正しいモデルである2次多項式モデルの選択頻度がAICおよびBICとも最も高いが、BICの方が正しいモデルである2次多項式モデルの選択がAICより多い。

次に、サンプルサイズを変えたときのAICBICによるモデル選択の頻度を調べてみる。

 

 

 

(2)サンプルサイズn_pnts=20, 100, 1000のときのAICおよびBIC

 

サンプルサイズn_pnts=100の条件の他に、それよりサンプルサイズが小さいn_pnts=20の条件と、多いn_pnts=1000の条件についても調べる。スクリプトはリスト2に示すものである。各サンプルサイズの条件において1000回のシミュレーションを行っている。スクリプトを実行すると図3のグラフが表示される。

図3

 

グラフは、AIC-サンプルサイズ、およびBIC-サンプルサイズごとに正しいモデルとして選択されたモデルの頻度が描かれているが、条件ごとの区別が分かり易いように折れ線グラフで描かれている。AICおよびBICともに、サンプルサイズが大きくなると正しい2次多項式モデルの選択される頻度が高くなることが示されている。また、AICおよびBICともに、サンプルサイズが20の場合に比べて、100の場合は正しいモデルの選択頻度が高くなっているが、サンプルサイズが100の場合と1000の場合とでは差は認め難い。頻度の値は、端末に出力されている。

 

(py311) PS D:\XXXXXXXX\aic_bic_simultn\samplefiles> python .\samplesize.py

 

sample size = 20

Degree                  0         1         2         3         4         5         6         7         8         9        10

Freq.(AIC)              0         0       425        81        67        54        55        58        51        80       129

Freq.(BIC)              0         0       700        86        51        34        26        19        23        22        39

 

sample size = 100

Degree                  0         1         2         3         4         5         6         7         8         9        10

Freq.(AIC)              0         0       681       107        68        57        24        13        25        13        12

Freq.(BIC)              0         0       959        36         2         3         0         0         0         0         0

 

sample size = 1000

Degree                  0         1         2         3         4         5         6         7         8         9        10

Freq.(AIC)              0         0       723       105        59        41        22        19        16         7         8

Freq.(BIC)              0         0       994         6         0         0         0         0         0         0         0

(py311) PS D:\XXXXXXXX\aic_bic_simultn\samplefiles>

 

 

 

リスト1 サンプルサイズn_pnts=100のときのAICBIC

 

import math

import numpy as np

import matplotlib.pyplot as plt

 

M =  5 

n = 1000

L = 4

n_pnts = 100

x = np.linspace(0, L, n_pnts)

f = x**2              #   True value

 

AICs = np.empty((n, M+1))

BICs = np.empty((n, M+1))

aic_choice_p = []

bic_choice_p = []

for i_trial in range(n):

    #    True value + Noise

    fn = f + 0.1 * np.random.normal(size=n_pnts)

    for p in range(M+1):

        A = np.empty((n_pnts, p+1))

        for j in range(p+1):

            A[:,j] = x ** j  

        b = np.linalg.pinv(A) @ fn

        f_pred = A @ b

        sse = np.sum((fn - f_pred)**2)

        sgm = (sse / n_pnts) ** 0.5

        max_log_L = -0.5 * n_pnts * math.log(2*math.pi) \

                    - n_pnts * math.log(sgm) \

                    -sse /(2 * (sgm**2))

        AICs[i_trial][p] = -2 * max_log_L + 2 * (p + 1 + 1)

        BICs[i_trial][p] = -2 * max_log_L + (p + 1 + 1) * math.log(n_pnts)

    c_aic = np.argmin(AICs[i_trial])

    aic_choice_p.append(c_aic)

    c_bic = np.argmin(BICs[i_trial])

    bic_choice_p.append(c_bic)

 

plt.figure(figsize=(12,5))

 

plt.subplot(1,2,1)

Mean_AICs = np.mean(AICs, axis=0)

plt.plot(range(M+1), Mean_AICs, '^-', c='r', lw=1, label='AIC(mean)')

Mean_BICs = np.mean(BICs, axis=0)

plt.plot(range(M+1), Mean_BICs, 'v-', c='g', lw=1, label='BIC(mean)')

plt.boxplot(AICs, positions=np.arange(0,M+1),boxprops={'color':'r'},

            flierprops={'markerfacecolor':'r'})

plt.boxplot(BICs, positions=np.arange(0,M+1),boxprops={'color':'g'},

            flierprops={'markerfacecolor':'g'})

plt.xticks(np.arange(0, M+1))

plt.xlabel('Polynomial Degree',fontsize=14)

plt.ylabel('Information Criterion', fontsize=14)

plt.title('Degree >= 0', fontsize=16)

plt.legend(fontsize=14)

 

plt.subplot(1,2,2)

plt.plot(np.arange(M+1)[2:], Mean_AICs[2:], '^-', c='r', lw=1,

         label='AIC(mean)')

plt.plot(np.arange(M+1)[2:], Mean_BICs[2:], 'v-', c = 'g', lw=1,

         label='BIC(mean)')

plt.xticks(np.arange(2, M+1))

plt.xlabel('Polynomial Degree', fontsize=14)

plt.ylabel('Information Criterion', fontsize=14)

plt.boxplot(AICs[:,2:], positions=np.arange(2, M+1), boxprops={'color':'r'},

            flierprops={'markerfacecolor':'r'})

plt.boxplot(BICs[:,2:], positions=np.arange(2, M+1), boxprops={'color':'g'},

            flierprops={'markerfacecolor':'g'}) 

plt.title('Degree >= 2', fontsize=16)

plt.legend()

plt.tight_layout()

plt.show()

 

plt.title('Model Selection', fontsize=16)

plt.hist([aic_choice_p, bic_choice_p], bins=np.arange(-0.5, M+1, 1.0),

         color=['r', 'g'], label=['AIC', 'BIC'])

plt.ylabel('Frequency', fontsize=14)

plt.xlabel('Degree', fontsize=14)

plt.legend(fontsize=14)

plt.tight_layout()

plt.show()

 

 

 

リスト2 サンプルサイズとモデルの選択頻度

 

import math

import numpy as np

import matplotlib.pyplot as plt

 

M =  10 

n = 1000

L = 4

 

choice_aic = np.zeros((3, M+1), dtype=int)

choice_bic = np.zeros((3, M+1), dtype=int)

n_pnts_L = [20, 100, 1000]

for i, n_pnts in enumerate(n_pnts_L):

    x = np.linspace(0, L, n_pnts)

    f = x**2              #   True value

    AICs = np.empty((n, M+1))

    BICs = np.empty((n, M+1))

    for i_trial in range(n):

        #    True value + Noise

        fn = f + 0.1 * np.random.normal(size=n_pnts)

        for p in range(M+1):

            A = np.empty((n_pnts, p+1))

            for j in range(p+1):

                A[:,j] = x ** j  

            b = np.linalg.pinv(A) @ fn

            f_pred = A @ b

            sse = np.sum((fn - f_pred)**2)

            sgm = (sse / n_pnts) ** 0.5

            max_log_L = -0.5 * n_pnts * math.log(2*math.pi) \

                        - n_pnts * math.log(sgm) \

                        -sse /(2 * (sgm**2))

            AICs[i_trial][p] = -2 * max_log_L + 2 * (p + 1 + 1)

            BICs[i_trial][p] = -2 * max_log_L + (p + 1 + 1) * math.log(n_pnts)

        c_aic = np.argmin(AICs[i_trial])

        choice_aic[i, c_aic] += 1

        c_bic = np.argmin(BICs[i_trial])

        choice_bic[i, c_bic] += 1

 

 

for i in range(3):

    print()

    print(f'sample size = {n_pnts_L[i]}')

    print(f'{"Degree": <15s}', end='')

    for j in range(M+1):

        print(f'{j:>10d}', end='')

    print()

    print(f'{"Freq.(AIC)":<15s}', end='')

    for j in range(M+1):

        print(f'{choice_aic[i,j]:>10d}', end='')

    print()

    print(f'{"Freq.(BIC)":<15s}', end='')

    for j in range(M+1):

        print(f'{choice_bic[i,j]:>10d}', end='')

    print()

 

 

lines = ['--', ':', '-']

for i in range(3):

    plt.plot(range(M+1), choice_aic[i], ls=lines[i], c='r',

             label=f'AIC-{n_pnts_L[i]}')

    plt.plot(range(M+1), choice_bic[i], ls=lines[i], c='g',

             label=f'BIC-{n_pnts_L[i]}')

plt.title('Model Selection', fontsize=16)

plt.ylabel('Frequency', fontsize=14)

plt.xlabel('Degree', fontsize=14)

plt.legend(fontsize=16)

plt.tight_layout()

plt.show()

 

 

 

参考文献

 

Brunton, S. L., and Kutz, J. N. (2019). Data-driven science and engineering: Machine learning, dynamic systems, and control. Cambridge University Press.

Konishi, S., and Kitagawa, G. (2008). Information criteria and statistical modeling. Springer.

岡本安晴(2009)統計学を学ぶための数学入門[下].培風館

岡本安晴(2019)いまさら聞けないPythonでデータ分析.丸善出版

 

 

 

Home