0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChatGPT と Python で学ぶ ベイズリッジ回帰 と 階層ベイズ回帰

Posted at

user:

ベイズ回帰と、その結果から、目的変数の変動に寄与する有意な相関関係を発見するためのPythonコードを書いてください。ダミーデータの変数名として、目的変数をY、説明変数をX_1, X_2, ... としてください。データのサンプル数が少なくても使える手法を選んでください。詳細かつ厳密にお願いします。

assistant:

ベイズ回帰を用いて、目的変数 ( Y ) の変動に寄与する有意な説明変数 ( X_1, X_2, \dots ) を発見するPythonコードを示します。少数サンプルでも安定して推定できるリッジ回帰(L2正則化)をベイズ的に解釈する Bayesian Ridge Regression を利用します。
また、MCMC(マルコフ連鎖モンテカルロ)を使う PyMC による階層ベイズ回帰も示します。


📌 手法の選択

  1. Bayesian Ridge Regression (Scikit-learn)

    • 少数データでも過学習を防げる。
    • 係数の不確実性(分布)を考慮できる。
    • 計算コストが低く実装が容易。
  2. 階層ベイズ回帰(PyMC3またはPyMC4)

    • 事前分布を自由に設定できる。
    • 変数の重要性を確率的に評価できる。
    • 計算コストは高いが、データが少なくても頑健。

コード

以下のコードでは、ダミーデータを作成し、ベイズ回帰を用いて有意な変数を特定します。

  1. ダミーデータを生成((X_1, X_2, X_3, Y))
  2. Bayesian Ridge Regression を適用
  3. PyMC を用いた階層ベイズ回帰
  4. 結果の可視化と有意な変数の特定

🔹 Bayesian Ridge Regression (Scikit-learn)

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import BayesianRidge

# ダミーデータ生成
np.random.seed(42)
n_samples = 20  # 少数サンプル
n_features = 3  # X_1, X_2, X_3
X = np.random.randn(n_samples, n_features)
true_coefs = np.array([1.5, -2.0, 0.0])  # X_3は影響なし
Y = X @ true_coefs + np.random.randn(n_samples) * 0.5  # ノイズ付き

# ベイズ回帰の適用
model = BayesianRidge()
model.fit(X, Y)

# 結果の表示
print("Bayesian Ridge Regression Coefficients:")
for i, coef in enumerate(model.coef_):
    print(f"X_{i+1}: {coef:.3f} ± {model.sigma_[i, i]**0.5:.3f}")

# 係数の分布を可視化
plt.bar([f'X_{i+1}' for i in range(n_features)], model.coef_, yerr=np.sqrt(np.diag(model.sigma_)))
plt.xlabel("Features")
plt.ylabel("Coefficient Value")
plt.title("Bayesian Ridge Regression Coefficients")
plt.show()

この結果から、標準誤差が小さくゼロと有意に異なる変数が、( Y ) に寄与していると考えられます。

さらに、PyMC を用いた MCMC による階層ベイズ回帰も実装できますが、興味がありますか?

user:

ありがとうございます。PyMC を用いた MCMC による階層ベイズ回帰もお願いします。

assistant:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pymc as pm
import arviz as az
from sklearn.linear_model import BayesianRidge

# ダミーデータ生成
np.random.seed(42)
n_samples = 20  # 少数サンプル
n_features = 3  # X_1, X_2, X_3
X = np.random.randn(n_samples, n_features)
true_coefs = np.array([1.5, -2.0, 0.0])  # X_3は影響なし
Y = X @ true_coefs + np.random.randn(n_samples) * 0.5  # ノイズ付き

# ベイズ回帰の適用(Bayesian Ridge Regression)
model = BayesianRidge()
model.fit(X, Y)

# 結果の表示
print("Bayesian Ridge Regression Coefficients:")
for i, coef in enumerate(model.coef_):
    print(f"X_{i+1}: {coef:.3f} ± {model.sigma_[i, i]**0.5:.3f}")

# 係数の分布を可視化
plt.bar([f'X_{i+1}' for i in range(n_features)], model.coef_, yerr=np.sqrt(np.diag(model.sigma_)))
plt.xlabel("Features")
plt.ylabel("Coefficient Value")
plt.title("Bayesian Ridge Regression Coefficients")
plt.show()

# 階層ベイズ回帰(PyMC)
with pm.Model() as bayesian_model:
    # 事前分布
    alpha = pm.Normal("alpha", mu=0, sigma=10)
    beta = pm.Normal("beta", mu=0, sigma=5, shape=n_features)
    sigma = pm.HalfNormal("sigma", sigma=1)
    
    # 線形モデル
    mu = alpha + pm.math.dot(X, beta)
    
    # 観測データ
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
    
    # MCMCサンプリング
    trace = pm.sample(2000, tune=1000, return_inferencedata=True)

# 結果の表示
az.plot_posterior(trace, var_names=["beta"])
plt.show()

# 係数の事後分布の要約
summary = az.summary(trace, var_names=["beta"])
print(summary)

PyMC を用いた MCMC による階層ベイズ回帰を追加しました。このコードでは、PyMC を使って係数の事後分布を推定し、ArviZ で可視化します。az.summary(trace, var_names=["beta"]) により、係数の事後分布の統計情報を確認できます。
次に確認したいことや改良点はありますか?

user:

ありがとうございます。次の結果が出ましたが、どう解釈すれば良いですか?

Progress                   Draws   Divergences   Step size   Grad evals   Sampling Speed    Elapsed   Remaining  
 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── 
  ━━━━━━━━━━━━━━━━━━━━━━━━   3000    0             0.93        7            1233.29 draws/s   0:00:02   0:00:00    
  ━━━━━━━━━━━━━━━━━━━━━━━━   3000    0             0.62        3            624.94 draws/s    0:00:04   0:00:00    
                                                                                                                   

          mean     sd  hdi_3%  hdi_97%  mcse_mean  mcse_sd  ess_bulk  \
beta[0]  1.238  0.200   0.877    1.631      0.003    0.002    4188.0   
beta[1] -1.980  0.139  -2.238   -1.717      0.002    0.002    3492.0   
beta[2] -0.071  0.156  -0.384    0.209      0.003    0.002    3720.0   

         ess_tail  r_hat  
beta[0]    2763.0    1.0  
beta[1]    2749.0    1.0  
beta[2]    2947.0    1.0  

assistant:

この結果の解釈は以下のようになります。

1. サンプリングの健全性

  • Divergences (発散): 0
    • 発散がないので、MCMC の収束がうまくいっている。
  • r_hat ≈ 1.0
    • すべての係数について r_hat が 1.0 なので、収束が確認できる。
  • ESS (Effective Sample Size)
    • ess_bulkess_tail が 2000 を大きく超えており、十分な有効サンプル数が確保されている。
    • MCMC の結果が信頼できる。

2. 各変数の影響

変数 平均 (mean) 標準偏差 (sd) 95% 信頼区間 (hdi_3% ~ hdi_97%)
β₀ (X_1) 1.238 0.200 (0.877, 1.631)
β₁ (X_2) -1.980 0.139 (-2.238, -1.717)
β₂ (X_3) -0.071 0.156 (-0.384, 0.209)

β₀ (X_1)

  • 1.238 ± 0.200 で、95% 信頼区間は (0.877, 1.631)
  • ゼロを含まないので、X_1 は 有意に Y に影響を与えている

β₁ (X_2)

  • -1.980 ± 0.139 で、95% 信頼区間は (-2.238, -1.717)
  • これもゼロを含まないので、X_2 も 有意に Y に影響を与えている

β₂ (X_3)

  • -0.071 ± 0.156 で、95% 信頼区間は (-0.384, 0.209)
  • ゼロを含むため、X_3 は Y に有意な影響を与えていない可能性が高い。

3. 結論

  • X_1 (β₀) と X_2 (β₁) は Y に統計的に有意な影響を与えている
  • X_3 (β₂) は Y に有意な影響を与えていない(影響が小さいか、ゼロに近い)。
  • 統計的に信頼できる結果が得られている。

次に、これを視覚的に分かりやすくするために、事後分布のヒストグラムや、各変数の影響度を可視化するプロットを追加しましょうか?

user:

はい、お願いします。

assistant:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pymc as pm
import arviz as az
from sklearn.linear_model import BayesianRidge

# ダミーデータ生成
np.random.seed(42)
n_samples = 20  # 少数サンプル
n_features = 3  # X_1, X_2, X_3
X = np.random.randn(n_samples, n_features)
true_coefs = np.array([1.5, -2.0, 0.0])  # X_3は影響なし
Y = X @ true_coefs + np.random.randn(n_samples) * 0.5  # ノイズ付き

# ベイズ回帰の適用(Bayesian Ridge Regression)
model = BayesianRidge()
model.fit(X, Y)

# 結果の表示
print("Bayesian Ridge Regression Coefficients:")
for i, coef in enumerate(model.coef_):
    print(f"X_{i+1}: {coef:.3f} ± {model.sigma_[i, i]**0.5:.3f}")

# 係数の分布を可視化
plt.bar([f'X_{i+1}' for i in range(n_features)], model.coef_, yerr=np.sqrt(np.diag(model.sigma_)))
plt.xlabel("Features")
plt.ylabel("Coefficient Value")
plt.title("Bayesian Ridge Regression Coefficients")
plt.show()

# 階層ベイズ回帰(PyMC)
with pm.Model() as bayesian_model:
    # 事前分布
    alpha = pm.Normal("alpha", mu=0, sigma=10)
    beta = pm.Normal("beta", mu=0, sigma=5, shape=n_features)
    sigma = pm.HalfNormal("sigma", sigma=1)
    
    # 線形モデル
    mu = alpha + pm.math.dot(X, beta)
    
    # 観測データ
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
    
    # MCMCサンプリング
    trace = pm.sample(2000, tune=1000, return_inferencedata=True)

# 結果の表示
az.plot_posterior(trace, var_names=["beta"])
plt.show()

# 係数の事後分布の要約
summary = az.summary(trace, var_names=["beta"])
print(summary)

# 事後分布のヒストグラム可視化
fig, axes = plt.subplots(1, n_features, figsize=(12, 4))
for i in range(n_features):
    az.plot_posterior(trace, var_names=[f"beta[{i}]"], ax=axes[i])
    axes[i].set_title(f"X_{i+1} (β_{i})")
plt.tight_layout()
plt.show()

事後分布のヒストグラムを追加しました。各変数 (X_1, X_2, X_3) の係数の分布を可視化し、影響の大きさを直感的に理解しやすくなっています。次に確認したい点や追加したい可視化はありますか?

user:

次のエラーを修正してください。

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/usr/local/lib/python3.11/dist-packages/arviz/utils.py in _var_names(var_names, data, filter_vars, errors)
     77         try:
---> 78             var_names = _subset_list(
     79                 var_names, all_vars, filter_items=filter_vars, warn=False, errors=errors

3 frames
KeyError: "['beta[0]'] are not present"

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
/usr/local/lib/python3.11/dist-packages/arviz/utils.py in _var_names(var_names, data, filter_vars, errors)
     81         except KeyError as err:
     82             msg = " ".join(("var names:", f"{err}", "in dataset"))
---> 83             raise KeyError(msg) from err
     84     return var_names
     85 

KeyError: 'var names: "[\'beta[0]\'] are not present" in dataset'

assistant:

エラーの原因は、PyMC の trace から取得する変数名の指定方法にあります。PyMC の trace では "beta" はそのままの形で格納されており、"beta[0]" のような個別のインデックス指定では参照できません。そのため、可視化の際に var_names=["beta"] のままにする必要があります。

修正点:

  1. az.plot_posterior(trace, var_names=["beta"]) を維持する。
  2. az.plot_posterior(trace, var_names=[f"beta[{i}]"], ax=axes[i])az.plot_posterior(trace.posterior.beta[:, i], ax=axes[i]) に変更する。

修正後のコードを適用します。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pymc as pm
import arviz as az
from sklearn.linear_model import BayesianRidge

# ダミーデータ生成
np.random.seed(42)
n_samples = 20  # 少数サンプル
n_features = 3  # X_1, X_2, X_3
X = np.random.randn(n_samples, n_features)
true_coefs = np.array([1.5, -2.0, 0.0])  # X_3は影響なし
Y = X @ true_coefs + np.random.randn(n_samples) * 0.5  # ノイズ付き

# ベイズ回帰の適用(Bayesian Ridge Regression)
model = BayesianRidge()
model.fit(X, Y)

# 結果の表示
print("Bayesian Ridge Regression Coefficients:")
for i, coef in enumerate(model.coef_):
    print(f"X_{i+1}: {coef:.3f} ± {model.sigma_[i, i]**0.5:.3f}")

# 係数の分布を可視化
plt.bar([f'X_{i+1}' for i in range(n_features)], model.coef_, yerr=np.sqrt(np.diag(model.sigma_)))
plt.xlabel("Features")
plt.ylabel("Coefficient Value")
plt.title("Bayesian Ridge Regression Coefficients")
plt.show()

# 階層ベイズ回帰(PyMC)
with pm.Model() as bayesian_model:
    # 事前分布
    alpha = pm.Normal("alpha", mu=0, sigma=10)
    beta = pm.Normal("beta", mu=0, sigma=5, shape=n_features)
    sigma = pm.HalfNormal("sigma", sigma=1)
    
    # 線形モデル
    mu = alpha + pm.math.dot(X, beta)
    
    # 観測データ
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
    
    # MCMCサンプリング
    trace = pm.sample(2000, tune=1000, return_inferencedata=True)

# 結果の表示
az.plot_posterior(trace, var_names=["beta"])
plt.show()

# 係数の事後分布の要約
summary = az.summary(trace, var_names=["beta"])
print(summary)

# 事後分布のヒストグラム可視化
fig, axes = plt.subplots(1, n_features, figsize=(12, 4))
for i in range(n_features):
    az.plot_posterior(trace.posterior["beta"].sel(beta_dim=i), ax=axes[i])
    axes[i].set_title(f"X_{i+1} (β_{i})")
plt.tight_layout()
plt.show()

エラーの原因となっていた beta[0] のような変数名の参照方法を修正しました。trace.posterior["beta"].sel(beta_dim=i) を使用することで、正しく変数を取得できるようになっています。これでエラーが解消されるはずです。動作を確認してみてください!

user:

上記コードをベースに、次のエラーを修正してください。

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-32-126527aac4f7> in <cell line: 0>()
     57 fig, axes = plt.subplots(1, n_features, figsize=(12, 4))
     58 for i in range(n_features):
---> 59     az.plot_posterior(trace.posterior["beta"].sel(beta_dim=i), ax=axes[i])
     60     axes[i].set_title(f"X_{i+1} (β_{i})")
     61 plt.tight_layout()

3 frames
/usr/local/lib/python3.11/dist-packages/xarray/core/indexing.py in group_indexers_by_index(obj, indexers, options)
    146             raise KeyError(f"no index found for coordinate {key!r}")
    147         elif key not in obj.dims:
--> 148             raise KeyError(
    149                 f"{key!r} is not a valid dimension or coordinate for "
    150                 f"{obj.__class__.__name__} with dimensions {obj.dims!r}"

KeyError: "'beta_dim' is not a valid dimension or coordinate for Dataset with dimensions FrozenMappingWarningOnValuesAccess({'chain': 2, 'draw': 2000, 'beta_dim_0': 3})"

assistant:

エラーの原因は、PyMC の tracebeta の次元名が "beta_dim_0" になっているためです。
そのため、sel(beta_dim=i) ではなく、正しい次元名を取得するよう修正する必要があります。

修正点:

  1. trace.posterior["beta"].dims で次元名を確認し、それに基づいて sel(...) を修正する。
  2. 一般的に trace.posterior["beta"] の次元は ("chain", "draw", "beta_dim_0") になっているので、beta_dim_0=i を指定する。

修正コードを適用します。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pymc as pm
import arviz as az
from sklearn.linear_model import BayesianRidge

# ダミーデータ生成
np.random.seed(42)
n_samples = 20  # 少数サンプル
n_features = 3  # X_1, X_2, X_3
X = np.random.randn(n_samples, n_features)
true_coefs = np.array([1.5, -2.0, 0.0])  # X_3は影響なし
Y = X @ true_coefs + np.random.randn(n_samples) * 0.5  # ノイズ付き

# ベイズ回帰の適用(Bayesian Ridge Regression)
model = BayesianRidge()
model.fit(X, Y)

# 結果の表示
print("Bayesian Ridge Regression Coefficients:")
for i, coef in enumerate(model.coef_):
    print(f"X_{i+1}: {coef:.3f} ± {model.sigma_[i, i]**0.5:.3f}")

# 係数の分布を可視化
plt.bar([f'X_{i+1}' for i in range(n_features)], model.coef_, yerr=np.sqrt(np.diag(model.sigma_)))
plt.xlabel("Features")
plt.ylabel("Coefficient Value")
plt.title("Bayesian Ridge Regression Coefficients")
plt.show()

# 階層ベイズ回帰(PyMC)
with pm.Model() as bayesian_model:
    # 事前分布
    alpha = pm.Normal("alpha", mu=0, sigma=10)
    beta = pm.Normal("beta", mu=0, sigma=5, shape=n_features)
    sigma = pm.HalfNormal("sigma", sigma=1)
    
    # 線形モデル
    mu = alpha + pm.math.dot(X, beta)
    
    # 観測データ
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
    
    # MCMCサンプリング
    trace = pm.sample(2000, tune=1000, return_inferencedata=True)

# 結果の表示
az.plot_posterior(trace, var_names=["beta"])
plt.show()

# 係数の事後分布の要約
summary = az.summary(trace, var_names=["beta"])
print(summary)

# 事後分布のヒストグラム可視化
beta_dim_name = [dim for dim in trace.posterior["beta"].dims if "beta_dim" in dim][0]  # 正しい次元名を取得
fig, axes = plt.subplots(1, n_features, figsize=(12, 4))
for i in range(n_features):
    az.plot_posterior(trace.posterior["beta"].sel({beta_dim_name: i}), ax=axes[i])
    axes[i].set_title(f"X_{i+1} (β_{i})")
plt.tight_layout()
plt.show()

エラーの原因となっていた beta_dim の名称を動的に取得し、正しく参照するように修正しました。これで KeyError が解消されるはずです。試してみてください!

user:

ありがとうございます。エラーなく終了しました。この手法は、説明変数の正規化が必要ですか?

assistant:

ベイズ回帰(特に PyMC を用いた MCMC による階層ベイズ回帰)では、説明変数の正規化(標準化: 平均0、分散1にスケール)は 推奨されます。以下の理由があります。

1. 事前分布のスケール調整

  • 事前分布(例えば beta ~ Normal(0, 5))は、標準化されていないデータに対して適切でない場合があります。
  • 例えば、ある変数のスケールが 0.01 で、別の変数のスケールが 1000 だと、共通の Normal(0, 5) の事前分布は適切でない可能性があります。

2. サンプリングの効率向上

  • PyMC の NUTS サンプラーは、スケールが異なる変数があると遷移しづらくなり、サンプリングの効率が低下します。
  • 変数のスケールを統一することで、収束が速くなり、事後分布の探索がスムーズになります。

3. 係数の解釈が容易

  • すべての変数が標準化されていると、係数の大きさを直接比較しやすくなります。
  • 標準化していない場合、係数の大きさは変数のスケールに依存するため、解釈が難しくなります。

ベストプラクティス

標準化(Zスコア変換)を行うには、以下の方法を追加するとよいでしょう。

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)  # Xを標準化

この X_scaled を PyMC のモデルに入力すると、より安定した推定が可能になります。


結論

正規化(標準化)は必須ではありませんが、推奨されます。
特に少数サンプルの場合、事後分布の収束や MCMC の効率を向上させるために、正規化を行うとよいでしょう。

user:

ありがとうございます。少数サンプルでも安定して推定できるリッジ回帰(L2正則化)をベイズ的に解釈する Bayesian Ridge Regression や、MCMC(マルコフ連鎖モンテカルロ)を使う PyMC による階層ベイズ回帰について、その理論に関して詳細かつ厳密に解説してください。

assistant:

Bayesian Ridge Regression(ベイズ的リッジ回帰)と、MCMC(マルコフ連鎖モンテカルロ)を用いた階層ベイズ回帰の理論について、厳密に解説します。


1. Bayesian Ridge Regression(ベイズ的リッジ回帰)

1.1. リッジ回帰の基本

リッジ回帰は、線形回帰に L2 正則化項を追加したものであり、次の目的関数を最小化します。

$\hat{\beta} = \arg\min_{\beta} \left{ \sum_{i=1}^{N} (y_i - X_i \beta)^2 + \lambda |\beta|^2 \right}$

ここで、

  • $ X \in \mathbb{R}^{N \times p}$は説明変数の行列((N) 個のサンプル、(p) 個の特徴量)
  • $ y \in \mathbb{R}^{N}$ は目的変数
  • $ \beta \in \mathbb{R}^{p} $ は回帰係数
  • $ \lambda > 0 $ は正則化パラメータ

通常の最小二乗推定では、係数 ( \beta ) の推定値がデータの分散に強く依存するため、少数サンプルでは過学習しやすいですが、リッジ回帰は正則化によってこの問題を軽減します。


1.2. ベイズ的リッジ回帰

ベイズ的解釈では、( \beta ) に事前分布を課し、事後分布を推定します。一般的には、以下のような正規分布の事前分布を仮定します。

$$
\beta \sim \mathcal{N}(0, \alpha^{-1} I)
$$

ここで、$\alpha$ は精度(precision; 分散の逆数)を表すハイパーパラメータです。

また、観測誤差 $ \varepsilon $ も正規分布に従うと仮定します。

$$
y \mid X, \beta, \lambda \sim \mathcal{N}(X\beta, \lambda^{-1} I)
$$

このとき、ベイズの定理を用いて ( \beta ) の事後分布を求めると、次のように正規分布の形を保ちます。

$$
p(\beta \mid X, y) = \mathcal{N}(\mu, \Sigma)
$$

この事後分布の平均 ( \mu ) と分散 ( \Sigma ) は、以下のように計算できます。

$$
\Sigma = (\lambda X^T X + \alpha I)^{-1}
$$

$$
\mu = \lambda \Sigma X^T y
$$

ここで、$ \lambda $ や $ \alpha $ も未知の場合、共役事前分布(例えばガンマ分布)を仮定し、最尤推定や周辺化(積分)によって推定することができます。

特徴:

  • 解析的に解けるため計算が高速
  • 少数サンプルでも安定した推定が可能
  • 係数の不確実性を考慮できる

2. MCMC(マルコフ連鎖モンテカルロ)による階層ベイズ回帰

Bayesian Ridge Regression は解析的に解けますが、より一般的な非線形モデルや階層ベイズモデルを扱う場合は、MCMC を用いた近似推論が必要になります。

2.1. 階層ベイズ回帰のモデル

MCMC によるベイズ回帰では、次のような確率モデルを仮定します。

  1. 事前分布(先験情報を表す)
    $$
    \alpha \sim \text{Gamma}(a_0, b_0)
    $$
    $$
    \sigma \sim \text{HalfNormal}(\tau)
    $$
    $$
    \beta_j \sim \mathcal{N}(0, \alpha^{-1})
    $$

  2. 尤度関数(データが得られる確率)
    $$
    y_i \mid X_i, \beta, \sigma \sim \mathcal{N}(X_i \beta, \sigma^2)
    $$

ここで、

  • 階層構造:$ \beta $ の分布を制御するハイパーパラメータ $ \alpha $ に事前分布を課している
  • 分散の事前分布:観測誤差の標準偏差 $ \sigma $ にも事前分布を課すことで、過度な過学習を防ぐ

2.2. MCMC による事後分布の推定

解析的に事後分布を求めることが困難な場合、MCMC によって事後分布を近似します。
PyMC では、NUTS(No-U-Turn Sampler) を用いることが一般的です。

NUTS の特徴:

  • 勾配を利用したサンプリング(HMC: Hamiltonian Monte Carlo の拡張)
  • チューニング不要で効率的に収束
  • 高次元パラメータ空間でも安定

MCMC のサンプルが十分に取得できると、以下のような事後分布が得られます。

$$
p(\beta \mid X, y)
$$

事後分布の形状を確認することで、各パラメータの不確実性も評価できます。


2.3. Bayesian Ridge Regression との比較

Bayesian Ridge Regression MCMC (PyMC)
計算方法 解析的に解く サンプリングによる近似
速度 高速 遅い(MCMC の収束に時間がかかる)
柔軟性 正規分布の仮定が必要 非線形モデルや階層構造に対応可能
パラメータの不確実性 正規分布の形で解析的に得られる 任意の事後分布の形で得られる

結論

  • Bayesian Ridge Regression は、少数サンプルでも安定した回帰が可能であり、高速な解析的手法として有用。
  • MCMC を用いた階層ベイズ回帰 は、柔軟なモデルを扱うのに適しており、事後分布の形状を詳細に評価できるが、計算コストが高い。

適用場面によって、どちらの手法を選択するかを決めるのが重要です。

user:

すみません、MCMC を用いた階層ベイズ回帰のどこが「階層」なのか、よく分からなかったので詳しく説明していただけますか?

assistant:

MCMC を用いた階層ベイズ回帰における「階層」の意味

階層ベイズ(Hierarchical Bayesian)回帰とは、パラメータが階層的な構造を持つモデル のことを指します。通常のベイズ回帰と異なり、パラメータ(回帰係数 β など)自体にも事前分布を持たせ、その事前分布のパラメータ(ハイパーパラメータ)にもさらに事前分布を与える ことで、より柔軟で頑健な推定が可能になります。


1. 階層構造の基本的な考え方

通常のベイズ回帰では、次のような事前分布を仮定します。

$$
\beta_j \sim \mathcal{N}(0, \sigma_{\beta}^2)
$$

しかし、この ( \sigma_{\beta}^2 ) を固定値にすると、データによっては適切でない場合があります。
→ そこで、( \sigma_{\beta}^2 ) にも事前分布を与え、データに応じて学習できるようにする のが階層ベイズです。


2. 階層ベイズ回帰のモデル

(1) 一般的な線形回帰モデル

まず、通常の線形回帰モデルを考えます。

$$
y_i = X_i \beta + \varepsilon_i, \quad \varepsilon_i \sim \mathcal{N}(0, \sigma^2)
$$

ここで、$ \beta $ に事前分布を設定するのがベイズ回帰 ですが、階層ベイズでは この事前分布のパラメータ(ハイパーパラメータ)もデータから学習するようにします


(2) 階層ベイズ回帰モデル

次のように 階層構造を持つ確率モデル を考えます。

第1層(観測データ)

$$
y_i \mid X_i, \beta, \sigma \sim \mathcal{N}(X_i \beta, \sigma^2)
$$

  • これは通常の回帰モデルと同じ。

第2層(回帰係数の事前分布)

$$
\beta_j \mid \tau^2 \sim \mathcal{N}(0, \tau^2)
$$

  • $ \beta $ の分散 $ \tau^2 $ にも未知のパラメータを設定
  • $ \beta $ の大きさをデータに適応させるための柔軟性を持たせる

第3層(ハイパーパラメータの事前分布)

$$
\tau \sim \text{HalfNormal}(\lambda)
$$

  • $ \tau $ にも事前分布を課すことで、$ \beta $ のスケールをデータから推定できるようにする
  • これにより、不要な説明変数の係数はゼロに近づきやすくなる(スパース化)

3. なぜ「階層」なのか?

通常のベイズ回帰では、係数 ( \beta ) のみに事前分布を設定するのに対し、階層ベイズ回帰では、その事前分布のパラメータ(ハイパーパラメータ)にも事前分布を設定する ため、「層(レイヤー)」が増える という意味で 「階層ベイズ」 と呼ばれます。

この 階層構造により、データが少ない場合でも適切な正則化が自然に行われ、頑健な推定が可能 になります。


4. PyMC による階層ベイズ回帰の具体例

上記の階層モデルを PyMC を使って実装すると、以下のようになります。

import pymc as pm
import numpy as np
import arviz as az

# ダミーデータ
np.random.seed(42)
n_samples = 20
n_features = 3
X = np.random.randn(n_samples, n_features)
true_coefs = np.array([1.5, -2.0, 0.0])
Y = X @ true_coefs + np.random.randn(n_samples) * 0.5  # ノイズあり

# 階層ベイズ回帰モデル
with pm.Model() as hierarchical_model:
    # 第3層(ハイパーパラメータの事前分布)
    tau = pm.HalfNormal("tau", sigma=1)

    # 第2層(回帰係数の事前分布)
    beta = pm.Normal("beta", mu=0, sigma=tau, shape=n_features)
    
    # ノイズの標準偏差(観測誤差)
    sigma = pm.HalfNormal("sigma", sigma=1)

    # 第1層(観測データ)
    mu = pm.math.dot(X, beta)
    Y_obs = pm.Normal("Y_obs", mu=mu, sigma=sigma, observed=Y)
    
    # MCMC によるサンプリング
    trace = pm.sample(2000, tune=1000, return_inferencedata=True)

# 結果の可視化
az.plot_posterior(trace, var_names=["beta", "tau"])
az.summary(trace, var_names=["beta", "tau"])

5. Bayesian Ridge Regression との違い

Bayesian Ridge Regression 階層ベイズ回帰(MCMC)
階層構造 なし(( \beta \sim \mathcal{N}(0, \alpha^{-1}) )) あり(( \tau ) に事前分布)
計算方法 解析的に解く MCMC によるサンプリング
柔軟性 正規分布の仮定が必要 より複雑なモデルに対応可能
正則化の自動調整 なし(固定パラメータ) あり(( \tau ) をデータから推定)
推定精度 少数サンプルでも安定 より頑健な推定が可能だが計算コストが高い

6. まとめ

階層ベイズ回帰の「階層」とは、事前分布のハイパーパラメータにも事前分布を与えること。
✅ これにより、データに適応した正則化が自動的に行われる
少数サンプルでも過学習を抑えつつ、スパース化が可能
計算コストは高いが、柔軟で解釈性の高い推定ができる

階層ベイズ回帰は、特に データが少ない場合や変数選択が重要な場面 で有効な手法です!

user:

ありがとうございました。大変勉強になりました!

assistant:

どういたしまして!お役に立ててよかったです 😊✨
ベイズ推論や MCMC は奥が深いので、さらに理解を深めたい場合は StanHamiltonian Monte Carlo (HMC) も調べてみると面白いですよ!

また何か質問があれば、いつでも聞いてくださいね!📊📈

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?