ホーム » ベイズ統計

ベイズ統計」カテゴリーアーカイブ

投稿一覧

2019 Q5(4)

前問の式をグラフに描画しました。

 

コード

グラフをプロットします。

# 2019 Q5(4)  2024.9.30

import numpy as np
import matplotlib.pyplot as plt

# μハット(事後分布のモード)を計算する関数
def mu_hat(y_mean, lambd, xi, n):
    if y_mean > xi:
        return max(y_mean - lambd / n, xi)
    elif y_mean < xi:
        return min(y_mean + lambd / n, xi)
    else:
        return xi

# パラメータ設定
xi = 0  # ラプラス分布の中央値
lambd = 1  # スケールパラメータ
n_samples = 5  # サンプル数

# ȳ(観測データの平均)の範囲を設定 (-1 から 1)
y_mean_values = np.linspace(-1, 1, 500)

# μハットの値を計算
mu_hat_values = [mu_hat(y_mean, lambd, xi, n_samples) for y_mean in y_mean_values]

# グラフをプロット
plt.plot(y_mean_values, mu_hat_values, label='μハット (事後分布のモード)', color='red')
plt.plot(y_mean_values, y_mean_values, label='ȳ (標本平均)', color='blue', linestyle='--')
plt.title(f'標本平均 ȳ と 推定値 μハットの比較 (ξ = {xi}, λ = {lambd}, n = {n_samples})')
plt.xlabel('ȳ (標本平均)')
plt.ylabel('μハット (推定値)')
plt.legend()
plt.grid(True)
plt.show()

\bar{y}がξに近いとき、\hat{\mu}はξになるという特徴があるようです。

2019 Q5(3)

前問の事後確率密度関数の最大値を取る期待値μを求めました。

 

コード

対数事後分布 h(μ)と、その第1項(観測データに基づく項)および第2項(事前分布に基づく項)のグラフを描画します。パラメータ ξ を 1 または 5、スケールパラメータ λ を 25 または 50 として、それぞれの組み合わせで描画します。

# 2019 Q5(3)  2024.9.29

import numpy as np
import matplotlib.pyplot as plt

# 対数事後分布の第1項: 観測データに基づく項
def h_term1(mu, y):
    n = len(y)
    y_mean = np.mean(y)
    return -0.5 * n * (mu - y_mean)**2

# 対数事後分布の第2項: 事前分布に基づく項
def h_term2(mu, lambd, xi):
    return -lambd * np.abs(mu - xi)

# 対数事後分布 h(μ) の定義
def h(mu, y, lambd, xi):
    return h_term1(mu, y) + h_term2(mu, lambd, xi)

# μハット(事後分布のモード)を計算
def mu_hat(y_mean, lambd, xi, n):
    if y_mean > xi:
        return max(y_mean - lambd / n, xi)
    elif y_mean < xi:
        return min(y_mean + lambd / n, xi)
    else:
        return xi

# パラメータ設定のリスト (xi, lambd) の組み合わせ
params = [(1, 25), (1, 50), (5, 25), (5, 50)]
n_samples = 20  # サンプル数
mu_values = np.linspace(0, 6, 500)  # μの範囲

# グラフを4つ表示するための設定
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

for i, (xi, lambd) in enumerate(params):
    # 観測データを生成して、平均を3に調整
    np.random.seed(43)
    y = np.random.normal(loc=3, scale=1, size=n_samples)
    y_mean = np.mean(y)
    
    # μハットを計算
    mu_hat_value = mu_hat(y_mean, lambd, xi, n_samples)

    # 各項の計算
    h_values = h(mu_values, y, lambd, xi)
    h_term1_values = h_term1(mu_values, y)
    h_term2_values = h_term2(mu_values, lambd, xi)

    # サブプロットに描画
    ax = axes[i//2, i%2]
    ax.plot(mu_values, h_values, label='h(μ)', color='orange')
    ax.plot(mu_values, h_term1_values, label='第1項: -n/2 (μ - ȳ)²', color='blue')
    ax.plot(mu_values, h_term2_values, label='第2項: -λ|μ - ξ|', color='green')
    
    # μハットを縦線でプロット
    ax.axvline(mu_hat_value, color='red', linestyle='--', label=f'μハット = {mu_hat_value:.2f}')

    # グラフのタイトル
    ax.set_title(f'ξ = {xi}, λ = {lambd}, ȳ = {y_mean:.2f}, n = {n_samples}')
    ax.set_xlabel('μ')
    ax.set_ylabel('値')
    ax.legend()
    ax.grid(True)

# グラフを描画
plt.tight_layout()
plt.show()

対数事後分布 h(μ)が最大値を取るμハットが

であることが確認できました。

2019 Q5(2)

ラプラス分布に従う確率変数μを母平均とする正規分布の観測値からμの事後確率密度関数を求めました。

 

コード

数式を使って事後確率密度関数g(μ|y)を求めます。

# 2019 Q5(2)  2024.9.28

import sympy as sp

# シンボリック変数の定義
mu, xi, lambd, n = sp.symbols('mu xi lambda n')
y = sp.IndexedBase('y')
i = sp.symbols('i', integer=True)

# ラプラス分布の事前分布
laplace_prior = (lambd / 2) * sp.exp(-lambd * sp.Abs(mu - xi))

# 正規分布の尤度関数
likelihood = (1 / (2 * sp.pi)**(n / 2)) * sp.exp(-sp.Sum((y[i] - mu)**2 / 2, (i, 1, n)))

# 事後分布 (比例定数は無視)
posterior = laplace_prior * likelihood

# 結果を簡略化
posterior_simplified = sp.simplify(posterior)

# 結果を表示
posterior_simplified

形は少し違いますが手計算の結果と一致しました。

次に、事前分布と事後分布の確率密度関数をプロットします。比較しやすいように事後分布は正規化します。また事前分布がない場合として尤度関数も重ねて描画してみましょう。

# 2019 Q5(2)  2024.9.28

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import simps

# 事前分布(ラプラス分布)の定義
def laplace_prior(mu, xi, lambd):
    return (lambd / 2) * np.exp(-lambd * np.abs(mu - xi))

# 事後分布(正規化定数は省略)
def posterior_example(mu, y, xi, lambd):
    n = len(y)
    y_mean = np.mean(y)
    sum_y = np.sum((y - y_mean)**2)
    
    # 解答例の事後分布
    return (lambd / (2 * (2 * np.pi)**(n / 2))) * np.exp(-0.5 * (sum_y + n * (mu - y_mean)**2) - lambd * np.abs(mu - xi))

# 尤度関数(事前分布がない場合)
def likelihood(mu, y):
    n = len(y)
    y_mean = np.mean(y)
    return np.exp(-0.5 * n * (mu - y_mean)**2)

# パラメータ設定
xi = 0  # ラプラス分布の中央値
lambd = 1  # スケールパラメータ
n_samples = 20  # サンプル数

# 観測データを生成
np.random.seed(43)
y = np.random.normal(loc=0, scale=1, size=n_samples)

# μの範囲を設定
mu_values = np.linspace(-3, 3, 500)

# 事前分布の計算
prior_values = laplace_prior(mu_values, xi, lambd)

# 事後分布の計算(事前分布あり)
posterior_values_example = posterior_example(mu_values, y, xi, lambd)

# 尤度関数の計算(事前分布なし)
likelihood_values = likelihood(mu_values, y)

# 事後分布と尤度関数を正規化
area_under_curve_example = simps(posterior_values_example, mu_values)  # 数値積分
posterior_values_example /= area_under_curve_example  # 正規化

area_under_likelihood = simps(likelihood_values, mu_values)  # 数値積分
likelihood_values /= area_under_likelihood  # 正規化

# グラフをプロット
plt.plot(mu_values, prior_values, label='事前分布 (ラプラス分布)', color='blue')
plt.plot(mu_values, posterior_values_example, label='事後分布', color='purple')
plt.plot(mu_values, likelihood_values, label='尤度関数(事前分布なし)', color='green', linestyle='--')
plt.title('事前分布、事後分布、および事前分布がない場合の尤度関数の比較')
plt.xlabel('μ')
plt.ylabel('確率密度')
plt.legend()
plt.show()

事後分布は事前分布と尤度関数の中間的な形をとっていることが分かります。

2021 Q2(4)

事前分布と尤度から事後確率が最大となるパラメータの推定値を求めました。

コード

数式を使った計算

# 2021 Q2(4)  2024.8.24

import numpy as np
from scipy.special import comb

# 事前分布 P(N_A)
def prior(NA):
    return NA + 1

# 尤度関数 P(X = 4 | N_A)
def likelihood(NA):
    return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)

# 事後分布 P(N_A | X = 4) (正規化定数は省略)
def posterior(NA):
    return prior(NA) * likelihood(NA)

# N_A の範囲
NA_values = np.arange(4, 90)

# 事後分布の計算
posterior_values = [posterior(NA) for NA in NA_values]

# 最大値を取る N_A (事後モード) を探索
NA_mode = NA_values[np.argmax(posterior_values)]

NA_mode
30

プロット

# 2021 Q2(4)  2024.8.24

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import comb

# 事前分布 P(N_A)
def prior(NA):
    return NA + 1

# 正規化定数
C = 1 / 5151

# 尤度関数 P(X = 4 | N_A)
def likelihood(NA):
    return comb(NA, 4) * comb(100 - NA, 11) / comb(100, 15)

# 事後分布 P(N_A | X = 4)
def posterior(NA):
    return prior(NA) * likelihood(NA)

# N_A の範囲を0から100まで(事前分布用)
NA_values_full = np.arange(0, 101)

# 事前分布を計算(0から100まで)
prior_values_full = [C * prior(NA) for NA in NA_values_full]

# N_A の範囲を4から89まで(事後分布用)
NA_values = np.arange(4, 90)

# 事後分布の計算
posterior_values = [posterior(NA) for NA in NA_values]

# 事後分布の正規化
posterior_sum = sum(posterior_values)
posterior_values_normalized = [value / posterior_sum for value in posterior_values]

# 事前分布が存在しない場合の事後分布(尤度のみを正規化)
likelihood_values = [likelihood(NA) for NA in NA_values]
likelihood_sum = sum(likelihood_values)
likelihood_values_normalized = [value / likelihood_sum for value in likelihood_values]

# 3つの分布を重ねて表示
plt.figure(figsize=(10, 6))

# 事前分布のプロット(0から100まで)
plt.plot(NA_values_full, prior_values_full, 'g-', label=r'事前分布 $P(N_A)$', markersize=5)

# 事後分布のプロット(4から89まで)
plt.plot(NA_values, posterior_values_normalized, 'bo-', label=r'事後分布 $P(N_A | X = 4)$', markersize=5)

# 事前分布が存在しない場合の事後分布(尤度のみ)
plt.plot(NA_values, likelihood_values_normalized, 'r-', label=r'事前分布なし $P(N_A | X = 4)$', markersize=5)

# 事後モードのプロット
NA_mode = NA_values[np.argmax(posterior_values_normalized)]
plt.axvline(NA_mode, color='blue', linestyle='--', label=f'事後モード: {NA_mode}')

# 事前分布なしの場合の最尤推定値のプロット
NA_mode_likelihood = NA_values[np.argmax(likelihood_values_normalized)]
plt.axvline(NA_mode_likelihood, color='red', linestyle=':', label=f'最尤推定値 (事前分布なし): {NA_mode_likelihood}')

# グラフの設定
plt.xlabel(r'$N_A$')
plt.ylabel(r'確率')
plt.title(r'事前分布ありとなしの比較')
plt.grid(True)
plt.legend()
plt.show()