以下の内容はhttps://www.anarchive-beta.com/entry/2021/03/17/104555より取得しました。


【Python】3.3.2:1次元ガウス分布のベイズ推論の実装:精度が未知の場合【緑ベイズ入門のノート】

はじめに

 『ベイズ推論による機械学習入門』(MLSシリーズ)の独学時のノートです。各種のモデルやアルゴリズムについて「数式・プログラム・図」を用いて解説します。
 本の補助として読んでください。

 この記事では、精度が未知の1次元ガウス分布に対するベイズ推論をPythonでスクラッチ実装します。

【前節の内容】

www.anarchive-beta.com

【他の節の内容】

www.anarchive-beta.com

【この節の内容】

3.3.2 1次元ガウス分布のベイズ推論の実装:精度が未知の場合

 1次元ガウスモデル(Gaussian model)に対するベイズ推論(Bayesian inference)を実装して、人工的に生成したデータを用いて、パラメータの学習と未知変数の予測を行う。この記事では、生成分布の精度パラメータ(precision parameter)が未知の場合を扱う。精度が未知の1次元ガウスモデルでは、尤度関数を1次元ガウス分布(Gaussian distribution・一変量正規分布・Normal distribution)、事前分布をガンマ分布(Gamma distribution)とする。この記事では、Pythonを利用して実装する。
 1次元ガウスモデルについては「3.3.0:1次元ガウスモデルの生成モデルの導出【緑ベイズ入門のノート】 - からっぽのしょこ」、ベイズ推論については「3.3.2:1次元ガウス分布のベイズ推論の導出:精度が未知の場合【緑ベイズ入門のノート】 - からっぽのしょこ」、Rを利用する場合は「【R】3.3.2:1次元ガウス分布のベイズ推論の実装:精度が未知の場合【緑ベイズ入門のノート】 - からっぽのしょこ」を参照のこと。

 利用するライブラリを読み込む。

# ライブラリを読込
import numpy as np
from scipy.stats import norm, gamma, t
import matplotlib.pyplot as plt


ベイズ推論の実装

 まずは、精度が未知の1次元ガウス分布に対するベイズ推論における一連の処理を確認する。
 生成モデル(精度が未知の1次元ガウスモデル)を設定して、モデルに従うデータ(トイデータ)を生成する。続いて、生成した観測データを用いて、事後分布の計算(パラメータの推定)を行う。さらに、事後分布のパラメータ(または観測データ)を用いて、予測分布の計算(未観測データの予測)を行う。

生成分布の設定

 データの生成分布(真の分布・ガウス分布)  p(x_n \mid \mu, \lambda_{\mathrm{truth}}) = \mathcal{N}(x_n \mid \mu, \lambda_{\mathrm{truth}}^{-1}) のパラメータ(真のパラメータ)  \mu, \lambda_{\mathrm{truth}} を設定する。 \mu は既知とする。
 ガウス分布については「【Python】1次元ガウス分布の作図 - からっぽのしょこ」を参照のこと。

 生成分布のパラメータ  \mu, \lambda_{\mathrm{truth}} を設定する。

# 既知のパラメータを指定
mu = 5.0

# 真のパラメータを指定
lambda_truth = 0.25
print(mu)
print(lambda_truth)
print(1.0/np.sqrt(lambda_truth))
5.0
0.25
2.0

 ガウス分布の平均パラメータ(実数)  \mu、精度パラメータ(正の値)  \lambda_{\mathrm{truth}} \gt 0 を指定する。
  \lambda_{\mathrm{truth}} がガウスモデルにおける真のパラメータであり、この値を求めるのがここでの目的(学習)である。

 生成分布の確率変数  x の作図範囲を設定する。

# x軸の範囲を設定
#x_min = -5.0
#x_max = 15.0
k = 4.0
u = 5.0
x_size  = 1.0/np.sqrt(lambda_truth) # 基準値を指定
x_size *= k # 定数倍
#x_size  = max(x_size, *np.abs(x_n-mu)) # サンプルと比較
x_size  = np.ceil(x_size /u)*u # u単位で切り上げ
x_min   = mu - x_size
x_max   = mu + x_size
print(x_min, x_max)

# x軸の値を作成
x_vec = np.linspace(start=x_min, stop=x_max, num=1001)
print(x_vec[:5])
-5.0 15.0
[-5.   -4.98 -4.96 -4.94 -4.92]

 この例では、指定したパラメータ(または生成したデータ)を使って、範囲を設定している。

 生成分布の確率密度を計算する。

# 生成分布の確率密度を計算:式(2.64)
model_dens_vec = norm.pdf(x=x_vec, loc=mu, scale=1.0/np.sqrt(lambda_truth))
print(model_dens_vec[:5])
[7.43359757e-07 7.81433554e-07 8.21375294e-07 8.63272261e-07
 9.07215595e-07]

  x の値ごとに、ガウス分布に従う確率密度  \mathcal{N}(x \mid \mu, \lambda_{\mathrm{truth}}^{-1}) を計算する。
 ガウス分布の確率密度関数 sp.stats.norm.pdf() の確率変数の引数 x x、平均の引数 loc \mu、標準偏差の引数 scale \sigma_{\mathrm{truth}} = \frac{1}{\sqrt{\lambda_{\mathrm{truth}}}} を指定する。

 生成分布のグラフを作成する。

# 生成分布のラベルを作成
model_param_lbl = f'$\\mu = {mu:.3g}, \\lambda_{{truth}} = {lambda_truth:.3g}$'

# 生成分布を作図
fig, ax = plt.subplots(
    figsize=(9, 6), dpi=100, facecolor='white', 
    constrained_layout=True
)
fig.suptitle('Gaussian distribution', fontsize=20)
ax.plot(
    x_vec, model_dens_vec, 
    color='red', linewidth=1.0, 
    label='true model', zorder=10
) # 真の分布
ax.set_xlabel('$x$')
ax.set_ylabel('density')
ax.set_title(model_param_lbl, loc='left') # パラメータラベル
ax.legend()
ax.grid(zorder=0)
plt.show()

生成分布(真の分布・1次元ガウス分布)のグラフ

 真の分布(ガウス分布)を赤色の曲線で示す。

 真のパラメータ  \lambda_{\mathrm{truth}} を求めることは、真の分布  \mathcal{N}(x_n \mid \mu, \lambda_{\mathrm{truth}}^{-1}) を求めることを意味する。

データの生成

 設定した生成分布(ガウス分布)  p(x_n \mid \mu, \lambda_{\mathrm{truth}}) = \mathcal{N}(x_n \mid \mu, \lambda_{\mathrm{truth}}^{-1}) に従うデータ(観測データ)  \mathbf{X} を作成する。
 ガウスモデルのデータ生成については「【Python】1次元ガウス分布の乱数生成 - からっぽのしょこ」を参照のこと。

 生成分布からデータ  \mathbf{X} を生成する。

# データ数を指定
N = 100

# 観測データを生成
x_n = np.random.normal(loc=mu, scale=1.0/np.sqrt(lambda_truth), size=N)
print(x_n[:10].round(1))
[3.8 3.8 5.9 3.8 6.4 2.7 1.8 8.6 4.9 7.3]

 データ数  N を指定して、ガウス分布に従う乱数  \mathbf{X} = \{x_1, \cdots, x_N\} を生成する。
 ガウス分布の乱数生成関数 np.random.normal() の平均の引数 loc \mu、標準偏差の引数 scale \sigma_{\mathrm{truth}} = \frac{1}{\sqrt{\lambda_{\mathrm{truth}}}}、サンプルサイズの引数 size N を指定する。

 観測データ  \mathbf{X} を集計する。

# 階級数を指定
bin_num = 40

# 階級幅を計算
bin_size = (x_max - x_min) / bin_num

# 境界値の範囲を設定
bin_min = x_min - 0.5*bin_size
bin_max = x_max + 0.5*bin_size

# 度数を集計
obs_freq_vec, bin_vec = np.histogram(a=x_n, bins=bin_num+1, range=(bin_min, bin_max))
print(obs_freq_vec[:5])

# 密度を計算
obs_dens_vec = obs_freq_vec / (bin_size * N)
print(obs_dens_vec[:5])

# 階級値を作成
center_vec = bin_vec[:-1] + 0.5*bin_size
print(center_vec[:5])
[0 0 0 0 0]
[0. 0. 0. 0. 0.]
[-5.  -4.5 -4.  -3.5 -3. ]

 階級数を指定して、階級幅  w を設定する。
  x の範囲で階級値を作成して、観測データ x_n に含まれる要素数をカウントして、度数  N_x と密度  \frac{N_x}{w N} を求める。

 観測データ  \mathbf{X} のグラフを作成する。

# 観測データのラベルを作成
obs_param_lbl  = f'$N = {N}, '
obs_param_lbl += f'\\mu = {mu:.3g}, \\lambda_{{truth}} = {lambda_truth:.3g}$'

# 密度軸の範囲を設定
u = 0.025
dens_max = np.max(obs_dens_vec)
dens_max = max(dens_max, model_dens_vec.max()) # 生成確率と比較
dens_max = np.ceil(dens_max /u)*u # u単位で切り上げ

# 観測データを作図
fig, ax = plt.subplots(
    figsize=(9, 6), dpi=100, facecolor='white', 
    constrained_layout=True
)
fig.suptitle('Gaussian distribution', fontsize=20)
ax2 = ax.twinx() # 第2軸の設定用

ax.plot(
    x_vec, model_dens_vec, 
    color='red', linewidth=1.0, linestyle='--', 
    label='true model\n(generation distribution)', zorder=10
) # 生成分布
ax.bar(
    x=center_vec, height=obs_dens_vec, 
    width=bin_size, align='center', 
    color='hotpink', alpha=0.5, 
    label='observation data', zorder=11
) # 観測データ

dens_vals = ax.get_yticks()        # 密度
freq_vals = dens_vals * bin_size*N # 度数
ax2.set_yticks(ticks=freq_vals, labels=[f'{y:.1f}' for y in freq_vals]) # 度数軸目盛
ax.set_xlabel('$x$')
ax.set_ylabel('density')
ax2.set_ylabel('frequency')
ax.set_title(obs_param_lbl, loc='left') # パラメータラベル
ax.legend()
ax.grid(zorder=0)
ax.set_ylim(ymin=0.0, ymax=dens_max) # (目盛の共通化用)
ax2.set_ylim(ymin=0.0, ymax=dens_max*bin_size*N) # (目盛の共通化用)

plt.show()

観測データ(1次元ガウス乱数)のグラフ

  x の値ごとの確率密度(生成分布)を赤色の曲線(破線)、観測データ  \mathbf{X} の度数  N_x (密度  \frac{N_x}{w N} )を桃色の棒グラフ(実線)で示す。

 データ数  N が十分に大きいと、観測データ  \mathbf{X} のヒストグラムの形状が生成分布  \mathcal{N}(x_n \mid \mu, \lambda_{\mathrm{truth}}^{-1}) に近付く。

事前分布の設定

 パラメータ  \lambda の事前分布(ガンマ分布)  p(\lambda \mid a, b) = \mathrm{Gam}(\lambda \mid a, b) のパラメータ(超パラメータ)  a, b を設定する。
 ガンマ分布については「【Python】ガンマ分布の作図 - からっぽのしょこ」を参照のこと。

 事前分布のパラメータ  a, b を設定する。

# 事前分布のパラメータを指定
a = 1.0
b = 1.0
print(a)
print(b)
1.0
1.0

 ガンマ分布の形状パラメータ(正の値)  a \gt 0、尺度パラメータ(正の値)  b \gt 0 を指定する。

 事前分布の確率変数  \lambda の作図範囲を設定する。

# λ軸の範囲を設定
lambda_min = 0.0
#lambda_max = 1.0
k = 3.0
u = 0.5
lambda_max = lambda_truth # 基準値を指定
lambda_max *= k # 定数倍
lambda_max = np.ceil(lambda_max /u)*u # u単位で切り上げ
print(lambda_min, lambda_max)

# λ軸の値を作成
lambda_vec = np.linspace(start=lambda_min, stop=lambda_max, num=1001)
print(lambda_vec[:5])
0.0 1.0
[0.    0.001 0.002 0.003 0.004]

 この例では、指定したパラメータを使って、範囲を設定している。

 事前分布の確率密度を計算する。

# 事前分布の確率密度を計算:式(2.56)
prior_dens_vec = gamma.pdf(x=lambda_vec, a=a, scale=1.0/b)
print(prior_dens_vec[:5])
[1.         0.9990005  0.998002   0.9970045  0.99600799]

  \lambda の値ごとに、ガンマ分布に従う確率密度  \mathrm{Gam}(\lambda \mid a, b) を計算する。
 ガンマ分布の確率密度関数 sp.stats.gamma.pdf() の確率変数の引数 x \lambda、形状の引数 a a、尺度の引数 scale \frac{1}{b} を指定する。

 事前分布のグラフを作成する。

# 事前分布のラベルを作成
prior_param_lbl  = f'$\\lambda_{{truth}} = {lambda_truth:.3g}, '
prior_param_lbl += f'a = {a:.3g}, b = {b:.3g}$'

# 事前分布を作図
fig, ax = plt.subplots(
    figsize=(9, 6), dpi=100, facecolor='white', 
    constrained_layout=True
)
fig.suptitle('Gamma distribution', fontsize=20)
ax2 = ax.twiny() # 第2軸の設定用

ax.axvline(
    x=lambda_truth, 
    color='red', linewidth=1.0, linestyle='--', 
    label='true parameter', zorder=10
) # 真のパラメータ
ax.plot(
    lambda_vec, prior_dens_vec, 
    color='purple', linewidth=1.0, 
    label='prior distribution', zorder=11
) # 事前分布

ax2.set_xticks(ticks=[lambda_truth], labels=['$\\lambda_{truth}$']) # パラメータラベル
ax.set_xlabel('$\\lambda$')
ax.set_ylabel('density')
ax.set_title(prior_param_lbl, loc='left') # パラメータラベル
ax.legend()
ax.grid(zorder=0)
ax.set_xlim(xmin=lambda_min, xmax=lambda_max) # (目盛の共通化用)
ax2.set_xlim(xmin=lambda_min, xmax=lambda_max) # (目盛の共通化用)

plt.show()

事前分布(ガンマ分布)のグラフ

 真のパラメータを赤色の垂直線(破線)、事前分布(ガンマ分布)を紫色の曲線(実線)で示す。

 真のパラメータ(真の分布のパラメータ)  \lambda_{\mathrm{truth}} と、パラメータ  \lambda の事前分布  \mathrm{Gam}(\lambda \mid a, b) の位置関係を図で確認する。

事後分布の計算

 観測データ  \mathbf{X} から、パラメータ  \lambda の事後分布(ガンマ分布)  p(\lambda \mid \mathbf{X}, \mu, a, b) = \mathrm{Gam}(\lambda \mid \hat{a}, \hat{b}) のパラメータ(超パラメータ)  \hat{a}, \hat{b} を求める(真のパラメータ  \lambda_{\mathrm{truth}} を分布推定する)。

 事後分布のパラメータ  \hat{a}, \hat{b} を計算する。

# 事後分布のパラメータを計算:式(3.53, 3.54)
a_hat = 0.5 * N + a
b_hat = 0.5 * np.sum((x_n - mu)**2) + b
print(a_hat)
print(b_hat)
51.0
193.8963541595772

 事後分布のパラメータは、観測データ  \mathbf{X} を用いて、次の式で計算できる。

 \displaystyle
\begin{aligned}
\hat{a}
   &= \frac{N}{2} + a
\\
\hat{b}
   &= \frac{1}{2}
      \sum_{n=1}^N (x_n - \mu)^2
      + b
\end{aligned}
\tag{3.69}

 事後分布の確率密度を計算する。

# 事後分布の確率密度を計算:式(2.56)
posterior_dens_vec = gamma.pdf(x=lambda_vec, a=a_hat, scale=1.0/b_hat)
print(posterior_dens_vec[:5])
[0.00000000e+00 1.25536151e-98 1.16428815e-83 6.11526542e-75
 8.89496053e-69]

 事前分布のときと同様にして、ガンマ分布に従う確率密度  \mathrm{Gam}(\lambda \mid \hat{a}, \hat{b}) を計算する。

 事後分布のグラフを作成する。

# 事後分布のラベルを作成
posterior_param_lbl  = f'$N = {N}, '
posterior_param_lbl += f'\\lambda_{{truth}} = {lambda_truth:.3g}, '
posterior_param_lbl += f'\\hat{{a}} = {a_hat:.3g}, \\hat{{b}} = {b_hat:.3g}$'

# 事後分布を作図
fig, ax = plt.subplots(
    figsize=(9, 6), dpi=100, facecolor='white', 
    constrained_layout=True
)
fig.suptitle('Gamma distribution', fontsize=20)
ax2 = ax.twiny() # 第2軸の設定用

ax.axvline(
    x=lambda_truth, 
    color='red', linewidth=1.0, linestyle='--', 
    label='true parameter', zorder=10
) # 真のパラメータ
ax.plot(
    lambda_vec, posterior_dens_vec, 
    color='purple', linewidth=1.0, 
    label='posterior distribution', zorder=11
) # 事後分布

ax2.set_xticks(ticks=[lambda_truth], labels=['$\\lambda_{truth}$']) # パラメータラベル
ax.set_xlabel('$\\lambda$')
ax.set_ylabel('density')
ax.set_title(posterior_param_lbl, loc='left') # パラメータラベル
ax.legend()
ax.grid(zorder=0)
ax.set_xlim(xmin=lambda_min, xmax=lambda_max) # (目盛の共通化用)
ax2.set_xlim(xmin=lambda_min, xmax=lambda_max) # (目盛の共通化用)

plt.show()

事後分布(ガンマ分布)のグラフ

 真のパラメータを赤色の垂直線(破線)、事後分布(ガンマ分布)を紫色の曲線(実線)で示す。

 データ数  N が十分に大きいと、パラメータ  \lambda の事後分布  \mathrm{Gam}(\lambda \mid \hat{a}, \hat{b}) のピークが真のパラメータ  \lambda_{\mathrm{truth}} に近付く。

予測分布の計算

 観測データ  \mathbf{X} から、未観測データ  x_{*} の予測分布(スチューデントのt分布)  p(x_{*} \mid \mathbf{X}, \mu, a, b) = \mathrm{St}(x_{*} \mid \mu_s, \hat{\lambda}_{s}, \hat{\nu}_s) のパラメータ  \mu_s, \hat{\lambda}_{s}, \hat{\nu}_s を求める。
 スチューデントのt分布については「【Python】1次元スチューデントのt分布の作図 - からっぽのしょこ」を参照のこと。

 予測分布のパラメータ  \mu_s, \hat{\lambda}_{s}, \hat{\nu}_s を計算する。

# 事後分布のパラメータにより予測分布のパラメータを計算:式(3.79')
mu_s         = mu
lambda_s_hat = a_hat / b_hat
nu_s_hat     = 2.0 * a_hat
print(mu_s)
print(lambda_s_hat)
print(nu_s_hat)
5.0
0.2630271219954289
102.0
# 観測データにより予測分布のパラメータを計算:式(3.79')
mu_s          = mu
lambda_s_hat  = N + 2.0 * a
lambda_s_hat /= np.sum((x_n - mu)**2) + 2.0 * b
nu_s_hat      = N + 2.0 * a
print(mu_s)
print(lambda_s_hat)
print(nu_s_hat)
5.0
0.2630271219954289
102.0

 予測分布のパラメータは、事後分布のパラメータ  \mu_s, \hat{\lambda}_s, \hat{\nu}_s または観測データ  \mathbf{X} を用いて、次の式で計算できる。

 \displaystyle
\begin{aligned}
\mu_s
   &= \mu
\\
\hat{\lambda}_s
   &= \frac{\hat{a}}{\hat{b}}
\\
   &= \frac{
          N + 2 a
      }{
          \sum_{n=1}^N (x_n - \mu)^2
          + 2 b
      }
\\
\hat{\nu}_s
   &=  2 \hat{a}
\\
   &= N + 2 a
\end{aligned}
\tag{3.79'}

 予測分布の確率密度を計算する。

# 予測分布の確率を計算:式(3.76)
predict_dens_vec = t.pdf(x=x_vec, df=nu_s_hat, loc=mu_s, scale=1.0/np.sqrt(lambda_s_hat))
print(predict_dens_vec[:5])
[1.50872171e-06 1.57376188e-06 1.64152385e-06 1.71211762e-06
 1.78565749e-06]

  x の値ごとに、スチューデントのt分布に従う確率密度  \mathrm{St}(x \mid \mu_s, \hat{\lambda}_s, \hat{\nu}_s) を計算する。
 スチューデントのt分布の確率密度関数 sp.stats.t.pdf() の確率変数の引数 x x、自由度の引数 nu \hat{\nu}_s、中心の引数 mu \mu_s、尺度の引数 sigma \hat{\sigma}_s = \frac{1}{\sqrt{\hat{\lambda}_s}} を指定する。

 予測分布のグラフを作成する。

# 予測分布のラベルを作成
predict_param_lbl  = f'$N = {N}, '
predict_param_lbl += f'\\mu = {mu:.3g}, \\lambda_{{truth}} = {lambda_truth:.3g}, '
predict_param_lbl += f'\\mu_s = {mu_s:.3g}, \\hat{{\\lambda}}_s = {lambda_s_hat:.3g}, \\hat{{\\nu}}_s = {nu_s_hat:.3g}$'

# 予測分布を作図
fig, ax = plt.subplots(
    figsize=(9, 6), dpi=100, facecolor='white', 
    constrained_layout=True
)
fig.suptitle("Student's t Distribution", fontsize=20)
ax.plot(
    x_vec, model_dens_vec, 
    color='red', linewidth=1.0, linestyle='--', 
    label='true model', zorder=10
) # 真の分布
ax.plot(
    x_vec, predict_dens_vec, 
    color='purple', linewidth=1.0, 
    label='predict distribution', zorder=11
) # 予測分布
ax.set_xlabel('$x$')
ax.set_ylabel('density')
ax.set_title(predict_param_lbl, loc='left') # パラメータラベル
ax.legend()
ax.grid(zorder=0)
plt.show()

事後予測分布(1次元スチューデントのt分布)のグラフ

 真の分布(ガウス分布)を赤色の曲線(破線)、予測分布(スチューデントのt分布)を紫色の曲線(実線)で示す。

 データ数  N が十分に大きいと、未観測データ  x_{*} の予測分布  \mathrm{St}(x_{*} \mid \mu_s, \hat{\lambda}_s, \hat{\nu}_s) の形状が真の分布  \mathcal{N}(x_{n} \mid \mu, \lambda_{\mathrm{truth}}) に近付く。

 以上で、精度が未知の1次元ガウスモデルのベイズ推論を実装した。

スポンサードリンク

学習の推移

 次は、1次元ガウス分布に対するベイズ推論を図で確認する。
 データ数を増やして分布の変化をアニメーションで確認する。
 作図コードについては「Suyama-Bayes/code/gaussian_model/bayesian_inference/plot_parameter_updates_unknown_precision.py at master · anemptyarchive/Suyama-Bayes · GitHub」を参照のこと。

データ数と分布の関係

 データ数  N を変化させたときの事後分布  p(\lambda \mid \mathbf{X}, \mu, a, b) の変化をアニメーションにする。

  n 個のデータから求めた(  n 回更新した)事後分布(ガンマ分布)  \mathrm{Gam}(\lambda \mid \hat{a}, \hat{b}) を紫色の曲線(実線)、 n 番目の観測データ  x_n に対応する位置  \lambda = (\frac{\sigma}{x_n - \mu})^2 を桃色の点で示す。

 「ベイズ推論の実装」では、 N 個(複数)のデータ  \mathbf{X} を用いて、事後分布のパラメータ  \hat{a}, \hat{b} を一括更新した。
  n 番目(1つ)のデータ  x_n を用いて逐次更新する場合、 n 回目の事後分布のパラメータ  a^{(n)}, b^{(n)} は、次の式で計算できる。

 \displaystyle
\begin{aligned}
a^{(n)}
   &\leftarrow
      \frac{1}{2}
      + a^{(n-1)}
\\
b^{(n)}
   &\leftarrow
      \frac{1}{2} (x\_n - \mu)^2
      + b^{(n-1)}
\end{aligned}

 超パラメータの初期値(1回目の更新における事前分布のパラメータ)を  a^{(0)}, b^{(0)} として、 a^{(n-1)}, b^{(n-1)} は、 n-1 回目の更新における事後分布のパラメータであり、また  n 回目の更新における事前分布のパラメータを表す。

 データ数  N が大きくなるのに応じて、パラメータ  \lambda の事後分布  \mathrm{Gam}(\lambda \mid \hat{a}, \hat{b}) のピークが真のパラメータ  \lambda_{\mathrm{truth}} に近付いていくのを確認できる。

 データ数  N を変化させたときの予測分布  p(x_{*} \mid \mathbf{X}, \mu, a, b) の変化をアニメーションにする。

  n 個のデータから求めた(  n 回更新した)予測分布(スチューデントのt分布)  \mathrm{St}(x_{*} \mid \mu_s, \hat{\lambda}_s, \hat{\nu}_s) を紫色の曲線(実線)、 n 番目の観測データ  x_n を桃色の点で示す。

 「ベイズ推論の実装」では、 N 個(複数)のデータ  \mathbf{X} を用いて、予測分布のパラメータ  \mu_s, \hat{\lambda}_s, \hat{\nu}_s を一括更新した。
  n 番目(1つ)のデータ  x_n を用いて逐次更新する場合、 n 回目の予測分布のパラメータ  \mu_s^{(n)}, \lambda_s^{(n)}, \nu_s^{(n)} は、次の式で計算できる。

 \displaystyle
\begin{aligned}
\mu_s^{(n)}
   &= \mu_s^{(n-1)}
\\
\lambda_s^{(n)}
   &= \frac{a^{(n)}}{b^{(n)}}
\\
\nu_s^{(n)}
   &\leftarrow
      1 + \nu_s^{(n-1)}
\end{aligned}

 超パラメータの初期値  a^{(0)}, b^{(0)} を用いて求めたパラメータを  \mu_s^{(0)}, \lambda_s^{(0)}, \nu_s^{(0)} として、 \mu_s^{(n-1)}, \lambda_s^{(n-1)}, \nu_s^{(n-1)} n-1 回目の更新値を表す。

 データ数  N が大きくなるのに応じて、未観測データ  x_{*} の予測分布  \mathrm{St}(x_{*} \mid \mu_s, \hat{\lambda}_{*}, \hat{\nu}_s) の形状が真の分布  \mathcal{N}(x_n \mid \mu_{\mathrm{truth}}, \lambda^{-1}) に近付いていくのを確認できる。

観測データと分布の関係

 データ数  N の変化による観測データと事後分布、予測分布の関係をアニメーションにする。

 真の分布の期待値  \mathbb{E}[x_n] と真のパラメータ  \lambda_{\mathrm{truth}} の各図(分布)に対応する位置を赤色の垂直線(破線)、観測データの標本平均  \bar{x} を桃色の垂直線(破線)、事後分布の期待値  \mathbb{E}[\lambda] と予測分布の期待値  \mathbb{E}[x_{*}] を紫色の垂直線(破線)で示す。
 また、 \sigma 軸と  \lambda 軸、 \lambda 軸と  p(x) 軸の対応関係を恒等関数や変換曲線で示す。

 生成分布(ガウス分布)、事後分布(ガンマ分布)、予測分布(スチューデントのt分布)の期待値は、それぞれ次の式で計算できる。

 \displaystyle
\begin{aligned}
\mathbb{E}_{\mathcal{N}(x_n \mid \mu, \lambda_{\mathrm{truth}}^{-1})}[x]
   &= \mu
\\
\mathbb{E}_{\mathrm{Gam}(\lambda \mid \hat{a}, \hat{b})}[\lambda]
   &= \frac{\hat{a}}{\hat{b}}
\\
\mathbb{E}_{\mathrm{St}(x_{*} \mid \mu_s, \hat{\lambda}_s, \hat{\nu}_s)}[x]
   &= \mu_s
\\
   &= \mu
\end{aligned}

 真の分布  \mathcal{N}(x_n \mid \mu, \lambda_{\mathrm{truth}}^{-1}) や真のパラメータ  \lambda_{\mathrm{truth}} と、観測データ  \mathbf{X}、事後分布  \mathrm{Gam}(\lambda \mid \hat{a}, \hat{b})、予測分布  \mathrm{St}(x_{*} \mid \mu_s, \hat{\lambda}_s, \hat{\nu}_s)、またそれぞれの統計量の対応関係を確認できる。

 以上で、精度が未知の1次元ガウスモデルのベイズ推論における学習推移を確認した。

 この記事では、精度が未知の場合の1次元ガウス分布に対するベイズ推論を扱った。次の記事では、平均と精度が未知の場合を扱う。

参考文献

おわりに

 Python歴もそろそろ1年になります。こうやってスクラッチで組むことしかしてないので、未だにNumPyとPyplotしかほとんど触ったことがない。

  • 2026.01.18:加筆修正しました。

 未だにスクラッチ実装ばかりしているので、Pandasすらまともに使えないままです。えっと今どきはPolarsなんでしたっけ。

 最後に、えびちゅうのライブ映像を1曲をどうぞ♪


【次節の内容】

  • 数式読解編

 1次元ガウスモデルに対するベイズ推論を数式で確認します。

www.anarchive-beta.com


  • スクラッチ実装編

 1次元ガウスモデルに対するベイズ推論をプログラムで確認します。

www.anarchive-beta.com




以上の内容はhttps://www.anarchive-beta.com/entry/2021/03/17/104555より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14