ベイズファクターとベイズ検定の理論を解説

頻度論的な仮説検定では、p値を用いて帰無仮説を棄却するかどうかを判定します。しかし、p値は「帰無仮説が正しい場合に今回のデータ以上に極端な結果が得られる確率」であり、「帰無仮説が正しい確率」を直接教えてくれるわけではありません。

ベイズファクター(Bayes Factor) は、この限界を克服するベイズ統計学に基づく仮説比較の枠組みです。2つの仮説(モデル)の 周辺尤度(marginal likelihood) の比として定義され、データがどちらの仮説をどれだけ支持するかを直接的に定量化します。ベイズファクターは、帰無仮説を「支持する」方向の証拠も評価できるという点で、p値にはない対称性を持っています。

本記事の内容

  • ベイズファクターの定義(周辺尤度の比)
  • 事後オッズと事前オッズの関係
  • ジェフリーズのスケールによる解釈
  • 周辺尤度の計算方法(解析的計算とモンテカルロ法)
  • 正規分布の平均検定でのベイズファクター
  • p値との比較
  • Pythonでの実装

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

ベイズファクターとは

直感的な理解

2つのモデル(仮説)$M_1$ と $M_2$ があり、データ $\bm{x}$ がどちらのモデルをより強く支持するかを比較したいとします。

各モデルのもとで「データ $\bm{x}$ がどれくらいもっともらしいか」を測る指標が 周辺尤度(marginal likelihood) です。ベイズファクターは、この周辺尤度の比です。

$$ BF_{12} = \frac{P(\bm{x} \mid M_1)}{P(\bm{x} \mid M_2)} $$

$BF_{12} > 1$ であれば $M_1$ が $M_2$ よりもデータによって支持されており、$BF_{12} < 1$ であれば $M_2$ が支持されています。

周辺尤度の定義

モデル $M_j$ がパラメータ $\bm{\theta}_j$ を持つとき、周辺尤度は尤度を事前分布で積分したものです。

$$ P(\bm{x} \mid M_j) = \int P(\bm{x} \mid \bm{\theta}_j, M_j) \cdot \pi(\bm{\theta}_j \mid M_j) \, d\bm{\theta}_j $$

ここで、

  • $P(\bm{x} \mid \bm{\theta}_j, M_j)$ はパラメータ $\bm{\theta}_j$ のもとでの尤度
  • $\pi(\bm{\theta}_j \mid M_j)$ はパラメータの事前分布

周辺尤度は「パラメータの不確実性を事前分布で平均化した尤度」と解釈できます。これが「周辺」と呼ばれる理由は、パラメータを 周辺化(marginalize out) しているためです。

ベイズファクターの正式な定義

$$ BF_{12} = \frac{P(\bm{x} \mid M_1)}{P(\bm{x} \mid M_2)} = \frac{\displaystyle\int P(\bm{x} \mid \bm{\theta}_1, M_1) \pi(\bm{\theta}_1 \mid M_1) \, d\bm{\theta}_1}{\displaystyle\int P(\bm{x} \mid \bm{\theta}_2, M_2) \pi(\bm{\theta}_2 \mid M_2) \, d\bm{\theta}_2} $$

事後オッズと事前オッズの関係

ベイズの定理のモデル版

各モデルの事後確率はベイズの定理から、

$$ P(M_j \mid \bm{x}) = \frac{P(\bm{x} \mid M_j) P(M_j)}{P(\bm{x})} $$

2つのモデルの事後確率の比(事後オッズ)は、

$$ \frac{P(M_1 \mid \bm{x})}{P(M_2 \mid \bm{x})} = \frac{P(\bm{x} \mid M_1)}{P(\bm{x} \mid M_2)} \cdot \frac{P(M_1)}{P(M_2)} $$

オッズの分解

$$ \underbrace{\frac{P(M_1 \mid \bm{x})}{P(M_2 \mid \bm{x})}}_{\text{事後オッズ}} = \underbrace{BF_{12}}_{\text{ベイズファクター}} \times \underbrace{\frac{P(M_1)}{P(M_2)}}_{\text{事前オッズ}} $$

この関係式は非常に重要です。

  • 事前オッズ: データを見る前の2つのモデルへの確信の比
  • ベイズファクター: データによる証拠の強さ
  • 事後オッズ: データを見た後のモデルへの確信の比

ベイズファクターは、事前の信念をデータによってどれだけ更新すべきかを示す「証拠の重み」です。事前オッズが等しい($P(M_1) = P(M_2) = 0.5$)場合、事後オッズはベイズファクターそのものになります。

ジェフリーズのスケール

Harold Jeffreysは、ベイズファクターの大きさを解釈するための目安を提案しました。

$BF_{12}$ $\log_{10} BF_{12}$ $M_1$ を支持する証拠の強さ
1 〜 3.2 0 〜 0.5 わずかな証拠(Barely worth mentioning)
3.2 〜 10 0.5 〜 1 実質的な証拠(Substantial)
10 〜 32 1 〜 1.5 強い証拠(Strong)
32 〜 100 1.5 〜 2 非常に強い証拠(Very strong)
> 100 > 2 決定的な証拠(Decisive)

$BF_{12} < 1$ の場合は $M_2$ を支持しており、$1/BF_{12}$ をジェフリーズのスケールに当てはめて解釈します。

周辺尤度の計算方法

解析的計算(共役事前分布)

事前分布と尤度が共役関係にある場合、周辺尤度は閉じた形で計算できます。

正規分布・正規事前分布の場合

データ $x_1, \dots, x_n \sim N(\mu, \sigma^2)$($\sigma^2$ 既知)で、$\mu$ の事前分布を $\mu \sim N(\mu_0, \tau^2)$ とします。

尤度は

$$ P(\bm{x} \mid \mu) = \prod_{i=1}^{n} \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x_i – \mu)^2}{2\sigma^2}\right) = (2\pi\sigma^2)^{-n/2} \exp\left(-\frac{\sum(x_i – \mu)^2}{2\sigma^2}\right) $$

事前分布は

$$ \pi(\mu) = \frac{1}{\sqrt{2\pi\tau^2}} \exp\left(-\frac{(\mu – \mu_0)^2}{2\tau^2}\right) $$

周辺尤度は

$$ P(\bm{x}) = \int_{-\infty}^{\infty} P(\bm{x} \mid \mu) \pi(\mu) \, d\mu $$

この積分を計算します。指数部分をまとめると、

$$ -\frac{\sum(x_i – \mu)^2}{2\sigma^2} – \frac{(\mu – \mu_0)^2}{2\tau^2} $$

$\sum(x_i – \mu)^2 = \sum(x_i – \bar{x})^2 + n(\bar{x} – \mu)^2$ を代入すると、

$$ -\frac{\sum(x_i – \bar{x})^2}{2\sigma^2} – \frac{n(\bar{x} – \mu)^2}{2\sigma^2} – \frac{(\mu – \mu_0)^2}{2\tau^2} $$

$\mu$ に依存する部分のみ抜き出すと、

$$ -\frac{1}{2}\left(\frac{n}{\sigma^2} + \frac{1}{\tau^2}\right)\mu^2 + \left(\frac{n\bar{x}}{\sigma^2} + \frac{\mu_0}{\tau^2}\right)\mu + \text{const} $$

$A = \frac{n}{\sigma^2} + \frac{1}{\tau^2}$ とおくと、これは $\mu$ に関する正規分布の指数部です。

ガウス積分 $\int_{-\infty}^{\infty} \exp(-\frac{A}{2}\mu^2 + B\mu) \, d\mu = \sqrt{\frac{2\pi}{A}} \exp\left(\frac{B^2}{2A}\right)$ を用いると、

$$ P(\bm{x}) = (2\pi\sigma^2)^{-n/2} \cdot \frac{1}{\sqrt{2\pi\tau^2}} \cdot \sqrt{\frac{2\pi}{A}} \cdot \exp\left(-\frac{\sum(x_i – \bar{x})^2}{2\sigma^2} + \frac{B^2}{2A}\right) $$

ここで $B = \frac{n\bar{x}}{\sigma^2} + \frac{\mu_0}{\tau^2}$ です。

整理すると、$1/A = \frac{\sigma^2\tau^2}{n\tau^2 + \sigma^2}$ なので、

$$ P(\bm{x}) = (2\pi\sigma^2)^{-n/2} \cdot \frac{1}{\sqrt{n\tau^2/\sigma^2 + 1}} \cdot \exp\left(-\frac{\sum(x_i – \bar{x})^2}{2\sigma^2} – \frac{(\bar{x} – \mu_0)^2}{2(\sigma^2/n + \tau^2)}\right) $$

最後の指数部分は、$\bar{x}$ の周辺分布が $\bar{x} \sim N(\mu_0, \sigma^2/n + \tau^2)$ であることを反映しています。

モンテカルロ法

共役事前分布でない場合は、モンテカルロ法で周辺尤度を近似します。

単純モンテカルロ法

事前分布 $\pi(\theta)$ から $M$ 個の標本 $\theta^{(1)}, \dots, \theta^{(M)}$ を生成し、

$$ P(\bm{x} \mid M_j) \approx \frac{1}{M}\sum_{m=1}^{M} P(\bm{x} \mid \theta^{(m)}, M_j) $$

これは $E_{\pi}[P(\bm{x} \mid \theta)]$ のモンテカルロ推定です。

問題点

単純モンテカルロ法は、事前分布と事後分布が大きく異なる場合に効率が悪くなります。事前分布からサンプリングした $\theta$ の多くは尤度が低い領域にあるため、多数の標本が必要になります。

ハーモニック平均法

事後分布からのサンプル $\theta^{(1)}, \dots, \theta^{(M)}$(MCMCの出力)を使って周辺尤度を推定する方法です。

$$ \frac{1}{P(\bm{x})} = E_{\text{post}}\left[\frac{1}{P(\bm{x} \mid \theta)}\right] $$

したがって、

$$ P(\bm{x}) \approx \left[\frac{1}{M}\sum_{m=1}^{M} \frac{1}{P(\bm{x} \mid \theta^{(m)})}\right]^{-1} $$

ただし、ハーモニック平均法は分散が非常に大きくなりやすく、実用上は推奨されません。

ブリッジサンプリング

より精度の高い方法として ブリッジサンプリング があります。事前分布と事後分布の両方からのサンプルを使い、最適なブリッジ関数を介して周辺尤度を推定します。

正規分布の平均検定でのベイズファクター

問題設定

データ $x_1, \dots, x_n \sim N(\mu, \sigma^2)$ に対して、

$$ M_0: \mu = \mu_0 \quad \text{vs} \quad M_1: \mu \neq \mu_0 $$

$\sigma^2$ は既知とします。$M_1$ のもとでは $\mu$ の事前分布を $\mu \sim N(\mu_0, \tau^2)$ とします($M_0$ のもとでは $\mu = \mu_0$ で固定なのでパラメータなし)。

$M_0$ の周辺尤度

$M_0$ のもとではパラメータが固定されているので、

$$ P(\bm{x} \mid M_0) = \prod_{i=1}^{n} \frac{1}{\sqrt{2\pi\sigma^2}} \exp\left(-\frac{(x_i – \mu_0)^2}{2\sigma^2}\right) $$

$$ = (2\pi\sigma^2)^{-n/2}\exp\left(-\frac{\sum(x_i – \mu_0)^2}{2\sigma^2}\right) $$

$M_1$ の周辺尤度

前節で導出した結果を使います。

$$ P(\bm{x} \mid M_1) = (2\pi\sigma^2)^{-n/2} \cdot \frac{1}{\sqrt{n\tau^2/\sigma^2 + 1}} \cdot \exp\left(-\frac{\sum(x_i – \bar{x})^2}{2\sigma^2} – \frac{(\bar{x} – \mu_0)^2}{2(\sigma^2/n + \tau^2)}\right) $$

ベイズファクターの導出

$$ BF_{01} = \frac{P(\bm{x} \mid M_0)}{P(\bm{x} \mid M_1)} $$

分子と分母で共通の $(2\pi\sigma^2)^{-n/2}$ は約分されます。

$$ \begin{align} BF_{01} &= \sqrt{n\tau^2/\sigma^2 + 1} \cdot \exp\left(-\frac{\sum(x_i – \mu_0)^2}{2\sigma^2} + \frac{\sum(x_i – \bar{x})^2}{2\sigma^2} + \frac{(\bar{x} – \mu_0)^2}{2(\sigma^2/n + \tau^2)}\right) \end{align} $$

$\sum(x_i – \mu_0)^2 = \sum(x_i – \bar{x})^2 + n(\bar{x} – \mu_0)^2$ を使うと、

$$ \begin{align} BF_{01} &= \sqrt{1 + n\tau^2/\sigma^2} \cdot \exp\left(-\frac{n(\bar{x} – \mu_0)^2}{2\sigma^2} + \frac{(\bar{x} – \mu_0)^2}{2(\sigma^2/n + \tau^2)}\right) \end{align} $$

指数部分を整理します。$r = n\tau^2/\sigma^2$ とおくと、$\sigma^2/n + \tau^2 = \sigma^2(1 + r)/n$ ですから、

$$ \frac{n(\bar{x} – \mu_0)^2}{2\sigma^2} – \frac{(\bar{x} – \mu_0)^2}{2\sigma^2(1+r)/n} = \frac{n(\bar{x} – \mu_0)^2}{2\sigma^2}\left(1 – \frac{1}{1+r}\right) = \frac{n(\bar{x} – \mu_0)^2}{2\sigma^2} \cdot \frac{r}{1+r} $$

z統計量 $z = \frac{\bar{x} – \mu_0}{\sigma/\sqrt{n}}$ を使うと、$n(\bar{x} – \mu_0)^2/\sigma^2 = z^2$ なので、

$$ \boxed{BF_{01} = \sqrt{1 + r} \cdot \exp\left(-\frac{z^2}{2} \cdot \frac{r}{1 + r}\right)} $$

ここで $r = n\tau^2/\sigma^2$ です。

ベイズファクターの解釈

$BF_{01} > 1$: $M_0$(帰無仮説)を支持する証拠

$BF_{01} < 1$: $M_1$(対立仮説)を支持する証拠

$BF_{10} = 1/BF_{01}$ で、対立仮説を支持するベイズファクターに変換できます。

事前分布の幅 $\tau$ の影響

$r = n\tau^2/\sigma^2$ を通じて、事前分布の幅 $\tau$ がベイズファクターに影響します。

  • $\tau$ が大きい(広い事前分布): $M_1$ は広い範囲の $\mu$ に事前確率を分散させるため、データがない限り $M_0$ に有利になる(リンドレーのパラドックス
  • $\tau$ が小さい(狭い事前分布): $M_1$ の事前分布が $M_0$ と似てくるため、判別が難しくなる

p値との比較

根本的な違い

p値 ベイズファクター
定義 $P(\text{data以上に極端} \mid H_0)$ $P(\text{data} \mid M_1) / P(\text{data} \mid M_0)$
解釈 $H_0$ の否定の証拠 2つのモデルの相対的な支持度
$H_0$ の支持 不可(棄却しないだけ) 可能($BF_{01} > 1$)
事前分布 不要 必要
標本サイズ依存 $n \to \infty$ で $p \to 0$ モデルに応じて有限値に収束しうる

Lindley’s paradox

大標本では、p値とベイズファクターが矛盾する場合があります。

$n$ が非常に大きいとき、わずかな効果でも $p < 0.05$ で統計的に有意になります。しかし、ベイズファクターは対立仮説の事前分布の広がりにペナルティを課すため、$BF_{01} > 1$(帰無仮説を支持)となることがあります。

これを リンドレーのパラドックス と呼びます。p値が「有意」を示しても、ベイズファクターが「帰無仮説を支持」する場合、データは帰無仮説からのわずかな逸脱を示しているだけで、実質的に重要な差ではない可能性があります。

具体例

数値例

工場の製品の重量が設計値 $\mu_0 = 100$ g であるかを検定します。$\sigma = 5$ g(既知)、$n = 25$ 個の測定で $\bar{x} = 101.5$ g でした。

$M_1$ の事前分布: $\mu \sim N(100, 10^2)$($\tau = 10$)

z統計量:

$$ z = \frac{101.5 – 100}{5/\sqrt{25}} = \frac{1.5}{1.0} = 1.5 $$

パラメータ $r$:

$$ r = \frac{n\tau^2}{\sigma^2} = \frac{25 \times 100}{25} = 100 $$

ベイズファクター:

$$ BF_{01} = \sqrt{1 + 100} \cdot \exp\left(-\frac{1.5^2}{2} \cdot \frac{100}{101}\right) = \sqrt{101} \cdot \exp\left(-\frac{2.25}{2} \cdot 0.990\right) $$

$$ = 10.05 \times \exp(-1.114) = 10.05 \times 0.329 = 3.31 $$

$BF_{01} = 3.31 > 1$ であり、ジェフリーズのスケールでは「実質的な証拠」の境界付近で、帰無仮説を弱く支持しています。

一方、p値は $p = 2(1 – \Phi(1.5)) = 2 \times 0.0668 = 0.134$ であり、有意水準5%では帰無仮説を棄却しません。この場合はp値とベイズファクターの結論は一致しています。

Pythonでの実装

ベイズファクターの計算(正規分布・分散既知)

import numpy as np
from scipy import stats

def bayes_factor_normal_known_var(data, mu_0, sigma, tau):
    """
    正規分布の平均の検定に対するベイズファクター(分散既知)

    H0: μ = μ_0  vs  H1: μ ~ N(μ_0, τ²)

    Parameters
    ----------
    data : array-like
        標本データ
    mu_0 : float
        帰無仮説のもとでの平均
    sigma : float
        母標準偏差(既知)
    tau : float
        対立仮説での事前分布の標準偏差

    Returns
    -------
    BF01 : float
        帰無仮説を支持するベイズファクター
    BF10 : float
        対立仮説を支持するベイズファクター
    """
    data = np.array(data, dtype=float)
    n = len(data)
    x_bar = np.mean(data)

    # z統計量
    z = (x_bar - mu_0) / (sigma / np.sqrt(n))

    # r パラメータ
    r = n * tau**2 / sigma**2

    # ベイズファクター BF01
    BF01 = np.sqrt(1 + r) * np.exp(-z**2 / 2 * r / (1 + r))
    BF10 = 1 / BF01

    return BF01, BF10


# --- 具体例 ---
np.random.seed(42)

mu_0 = 100   # 帰無仮説の母平均
sigma = 5.0  # 母標準偏差(既知)
tau = 10.0   # 事前分布の標準偏差
n = 25

# データ生成
data = np.random.normal(101.5, sigma, n)
x_bar = np.mean(data)
z = (x_bar - mu_0) / (sigma / np.sqrt(n))

BF01, BF10 = bayes_factor_normal_known_var(data, mu_0, sigma, tau)
p_value = 2 * (1 - stats.norm.cdf(np.abs(z)))

print("=== ベイズファクター vs p値 ===")
print(f"標本サイズ: n = {n}")
print(f"標本平均: x̄ = {x_bar:.4f}")
print(f"z統計量: z = {z:.4f}")
print(f"p値: {p_value:.4f}")
print()
print(f"BF₀₁ = {BF01:.4f} (H₀を支持)")
print(f"BF₁₀ = {BF10:.4f} (H₁を支持)")
print()

# ジェフリーズのスケール
if BF01 > 1:
    bf_for_scale = BF01
    direction = "H₀を支持"
else:
    bf_for_scale = BF10
    direction = "H₁を支持"

if bf_for_scale > 100:
    strength = "決定的"
elif bf_for_scale > 30:
    strength = "非常に強い"
elif bf_for_scale > 10:
    strength = "強い"
elif bf_for_scale > 3:
    strength = "実質的"
else:
    strength = "わずか"

print(f"ジェフリーズのスケール: {strength}な証拠で{direction}")

事前分布の幅がベイズファクターに与える影響

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(42)

# 固定パラメータ
mu_0 = 0
sigma = 1.0
n = 30

# z値を変えてBFを計算
z_values = np.linspace(0, 4, 100)
tau_values = [0.5, 1.0, 2.0, 5.0, 10.0]

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# BF10 vs z
for tau in tau_values:
    r = n * tau**2 / sigma**2
    BF01 = np.sqrt(1 + r) * np.exp(-z_values**2 / 2 * r / (1 + r))
    BF10 = 1 / BF01
    ax1.plot(z_values, BF10, linewidth=2, label=f'$\\tau$ = {tau}')

ax1.axhline(y=1, color='gray', linestyle='--', linewidth=1)
ax1.axhline(y=3, color='orange', linestyle=':', linewidth=1, label='BF = 3')
ax1.axhline(y=10, color='red', linestyle=':', linewidth=1, label='BF = 10')
ax1.set_xlabel('|z| statistic', fontsize=12)
ax1.set_ylabel('$BF_{10}$', fontsize=12)
ax1.set_title('Bayes Factor vs z-statistic', fontsize=13)
ax1.legend(fontsize=9)
ax1.grid(True, alpha=0.3)
ax1.set_yscale('log')
ax1.set_ylim(0.01, 1000)

# p値 vs BF10(固定 τ = 1)
tau = 1.0
r = n * tau**2 / sigma**2
BF01 = np.sqrt(1 + r) * np.exp(-z_values**2 / 2 * r / (1 + r))
BF10 = 1 / BF01
p_values = 2 * (1 - stats.norm.cdf(z_values))

ax2.plot(p_values, BF10, 'b-', linewidth=2)
ax2.axvline(x=0.05, color='red', linestyle='--', linewidth=1.5, label='p = 0.05')
ax2.axhline(y=1, color='gray', linestyle='--', linewidth=1)
ax2.axhline(y=3, color='orange', linestyle=':', linewidth=1, label='BF = 3')

# p = 0.05のときのBFを表示
z_005 = stats.norm.ppf(0.975)
BF01_005 = np.sqrt(1 + r) * np.exp(-z_005**2 / 2 * r / (1 + r))
BF10_005 = 1 / BF01_005
ax2.plot(0.05, BF10_005, 'ro', markersize=10)
ax2.annotate(f'p=0.05: BF₁₀={BF10_005:.2f}', xy=(0.05, BF10_005),
             xytext=(0.15, BF10_005*2), fontsize=10,
             arrowprops=dict(arrowstyle='->', color='red'))

ax2.set_xlabel('p-value', fontsize=12)
ax2.set_ylabel('$BF_{10}$', fontsize=12)
ax2.set_title(f'p-value vs Bayes Factor ($\\tau$ = {tau}, n = {n})', fontsize=13)
ax2.legend(fontsize=10)
ax2.grid(True, alpha=0.3)
ax2.set_yscale('log')
ax2.set_xlim(0, 0.5)

plt.tight_layout()
plt.show()

モンテカルロ法による周辺尤度の推定

import numpy as np
from scipy import stats

def marginal_likelihood_mc(data, mu_0, sigma, tau, M=100000, random_state=42):
    """
    単純モンテカルロ法による周辺尤度の推定

    Parameters
    ----------
    data : array-like
        標本データ
    mu_0 : float
        事前分布の平均
    sigma : float
        母標準偏差(既知)
    tau : float
        事前分布の標準偏差
    M : int
        モンテカルロサンプル数

    Returns
    -------
    ml_mc : float
        周辺尤度のモンテカルロ推定値
    ml_se : float
        推定値の標準誤差
    """
    rng = np.random.RandomState(random_state)
    data = np.array(data, dtype=float)
    n = len(data)

    # 事前分布からサンプリング
    mu_samples = rng.normal(mu_0, tau, M)

    # 各サンプルに対する対数尤度
    log_likes = np.zeros(M)
    for m in range(M):
        log_likes[m] = np.sum(stats.norm.logpdf(data, loc=mu_samples[m], scale=sigma))

    # 数値安定性のためにlog-sum-expトリック
    max_ll = np.max(log_likes)
    ml_mc = np.exp(max_ll) * np.mean(np.exp(log_likes - max_ll))

    # 標準誤差
    likes = np.exp(log_likes)
    ml_se = np.std(likes) / np.sqrt(M)

    return ml_mc, ml_se


# --- 具体例 ---
np.random.seed(42)

mu_0 = 100
sigma = 5.0
tau = 10.0
n = 25
data = np.random.normal(101.5, sigma, n)

# M0の周辺尤度(パラメータなし、直接計算)
log_ml_m0 = np.sum(stats.norm.logpdf(data, loc=mu_0, scale=sigma))
ml_m0 = np.exp(log_ml_m0)

# M1の周辺尤度(モンテカルロ推定)
ml_m1_mc, ml_m1_se = marginal_likelihood_mc(data, mu_0, sigma, tau, M=500000)

# M1の周辺尤度(解析解)
x_bar = np.mean(data)
r = n * tau**2 / sigma**2
marginal_var = sigma**2 / n + tau**2
log_ml_m1_exact = (np.sum(stats.norm.logpdf(data, loc=x_bar, scale=sigma))
                   + stats.norm.logpdf(x_bar, loc=mu_0, scale=np.sqrt(marginal_var))
                   - stats.norm.logpdf(x_bar, loc=x_bar, scale=sigma/np.sqrt(n)))

# ベイズファクター
BF01_mc = ml_m0 / ml_m1_mc
z = (x_bar - mu_0) / (sigma / np.sqrt(n))
BF01_exact = np.sqrt(1 + r) * np.exp(-z**2 / 2 * r / (1 + r))

print("=== 周辺尤度の計算方法の比較 ===")
print(f"\nM₀の周辺尤度(解析): log P(x|M₀) = {log_ml_m0:.4f}")
print(f"M₁の周辺尤度(MC):  P(x|M₁) = {ml_m1_mc:.4e} (SE = {ml_m1_se:.4e})")
print(f"\nBF₀₁(MC法):   {BF01_mc:.4f}")
print(f"BF₀₁(解析解): {BF01_exact:.4f}")

リンドレーのパラドックスの可視化

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# 標本サイズを変えたときのp値とBFの挙動
sample_sizes = np.arange(10, 2010, 10)
sigma = 1.0
tau = 1.0

# 固定された効果量: δ = 0.1(非常に小さな効果)
delta = 0.1
mu_0 = 0
mu_true = delta

p_values = []
BF01_values = []

for n in sample_sizes:
    # z統計量(母集団の効果から直接計算)
    se = sigma / np.sqrt(n)
    z = delta / se

    # p値
    p = 2 * (1 - stats.norm.cdf(z))
    p_values.append(p)

    # ベイズファクター
    r = n * tau**2 / sigma**2
    BF01 = np.sqrt(1 + r) * np.exp(-z**2 / 2 * r / (1 + r))
    BF01_values.append(BF01)

p_values = np.array(p_values)
BF01_values = np.array(BF01_values)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))

# p値の推移
ax1.plot(sample_sizes, p_values, 'b-', linewidth=2)
ax1.axhline(y=0.05, color='red', linestyle='--', linewidth=1.5,
            label='$\\alpha = 0.05$')
ax1.set_xlabel('Sample Size $n$', fontsize=12)
ax1.set_ylabel('p-value', fontsize=12)
ax1.set_title(f"Lindley's Paradox: p-value vs n (true $\\delta$ = {delta})", fontsize=14)
ax1.legend(fontsize=11)
ax1.grid(True, alpha=0.3)
ax1.set_yscale('log')

# n*のマーク(p < 0.05になる点)
n_star = sample_sizes[np.argmax(p_values < 0.05)]
ax1.axvline(x=n_star, color='green', linestyle=':', linewidth=1.5,
            label=f'p < 0.05 at n = {n_star}')
ax1.legend(fontsize=11)

# ベイズファクターの推移
ax2.plot(sample_sizes, BF01_values, 'r-', linewidth=2, label='$BF_{01}$')
ax2.axhline(y=1, color='gray', linestyle='--', linewidth=1)
ax2.axhline(y=3, color='orange', linestyle=':', linewidth=1,
            label='$BF_{01} = 3$ (substantial for $H_0$)')
ax2.axvline(x=n_star, color='green', linestyle=':', linewidth=1.5,
            label=f'p < 0.05 at n = {n_star}')
ax2.set_xlabel('Sample Size $n$', fontsize=12)
ax2.set_ylabel('$BF_{01}$', fontsize=12)
ax2.set_title(f"Lindley's Paradox: Bayes Factor vs n (true $\\delta$ = {delta}, $\\tau$ = {tau})",
              fontsize=14)
ax2.legend(fontsize=11)
ax2.grid(True, alpha=0.3)
ax2.set_yscale('log')

plt.tight_layout()
plt.show()

print(f"p値が0.05を下回るn: {n_star}")
print(f"そのときのBF01: {BF01_values[np.argmax(p_values < 0.05)]:.4f}")
print("→ p値は有意だが、BFは帰無仮説を支持する方向(リンドレーのパラドックス)")

異なる事前分布でのベイズファクターの感度分析

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

np.random.seed(42)

# データ生成
n = 50
sigma = 1.0
mu_0 = 0
data = np.random.normal(0.3, sigma, n)  # 小さな効果
x_bar = np.mean(data)
z = x_bar / (sigma / np.sqrt(n))
p_value = 2 * (1 - stats.norm.cdf(np.abs(z)))

print(f"x̄ = {x_bar:.4f}, z = {z:.4f}, p = {p_value:.4f}")

# 様々なτでベイズファクターを計算
tau_range = np.logspace(-2, 2, 200)

BF10_values = []
for tau in tau_range:
    r = n * tau**2 / sigma**2
    BF01 = np.sqrt(1 + r) * np.exp(-z**2 / 2 * r / (1 + r))
    BF10_values.append(1 / BF01)

fig, ax = plt.subplots(figsize=(10, 6))

ax.plot(tau_range, BF10_values, 'b-', linewidth=2.5)
ax.axhline(y=1, color='gray', linestyle='--', linewidth=1)
ax.axhline(y=3, color='orange', linestyle=':', linewidth=1, label='BF = 3')
ax.axhline(y=10, color='red', linestyle=':', linewidth=1, label='BF = 10')
ax.axhline(y=1/3, color='green', linestyle=':', linewidth=1, label='BF = 1/3')

# JZSベイズファクターに使われるτ=1の位置
ax.axvline(x=1, color='purple', linestyle='--', linewidth=1.5,
           label='$\\tau = 1$ (JZS default)')

ax.set_xlabel('Prior Width $\\tau$', fontsize=13)
ax.set_ylabel('$BF_{10}$', fontsize=13)
ax.set_title(f'Sensitivity Analysis: BF vs Prior Width (z = {z:.2f}, p = {p_value:.4f})',
             fontsize=14)
ax.set_xscale('log')
ax.set_yscale('log')
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)
ax.set_ylim(0.01, 100)

plt.tight_layout()
plt.show()

まとめ

本記事では、ベイズファクターとベイズ検定の理論について解説しました。

  • ベイズファクター: 2つのモデルの周辺尤度の比 $BF_{12} = P(\bm{x} \mid M_1) / P(\bm{x} \mid M_2)$
  • 事後オッズ: 事後オッズ = ベイズファクター $\times$ 事前オッズ
  • ジェフリーズのスケール: $BF > 3$(実質的)、$> 10$(強い)、$> 100$(決定的)
  • 周辺尤度: 尤度を事前分布で積分。共役事前分布なら解析的に計算可能、そうでなければモンテカルロ法
  • 正規分布の検定: $BF_{01} = \sqrt{1+r} \cdot \exp(-z^2 r / [2(1+r)])$($r = n\tau^2/\sigma^2$)
  • p値との違い: ベイズファクターは帰無仮説の支持も定量化でき、リンドレーのパラドックスでp値と矛盾することがある
  • 事前分布の影響: 事前分布の幅 $\tau$ が結果に影響するため、感度分析が重要

次のステップとして、以下の記事も参考にしてください。