cmdstanpyの環境構築と、サンプルコード(信用区間を用いた、2群の比率の差に関する推論)

pystanほどではないが、cmdstanpyでもライブラリ間のバージョン調整が必要だったので、メモ。
トレースプロットを描画しないなら環境構築でてこずらないが、
トレースプロットを描画するならarvizが必要になり、これによって、環境構築で不具合が出てくるようになった。
stanを使うときには、venvやdockerとか使って専用環境でやったほうがいいかも。

pythonは、3.9.16
各ライブラリは、以下のバージョン。
arviz 0.12.0
cmdstanpy 0.9.68
matplotlib 3.8.4
numpy 1.23.2
scipy 1.8.1

ーー

信用区間を用いた、2群の比率の差に関する推論(2群の比率の差の分布の95%信用区間がゼロをまたぐかどうか。跨いだら差がない。跨がなければ差がありその符号でどちらが勝ちかわかる。)
のサンプルコードを以下に示す。

import cmdstanpy
import numpy as np
import matplotlib.pyplot as plt
import arviz as az

# サンプルデータ: 2群の成功数と試行数
n1, y1 = 100, 60  # 群1: 100回の試行で60回成功
n2, y2 = 120, 7  # 群2: 120回の試行で7回成功

# Stanモデルの保存
stan_code = """
data {
  int<lower=0> n1;  // 群1のサンプルサイズ
  int<lower=0> y1;  // 群1の成功数
  int<lower=0> n2;  // 群2のサンプルサイズ
  int<lower=0> y2;  // 群2の成功数
}
parameters {
  real<lower=0, upper=1> theta1;  // 群1の成功率
  real<lower=0, upper=1> theta2;  // 群2の成功率
}
model {
  theta1 ~ beta(1, 1);  // 群1の成功率にベータ(1, 1)の事前分布
  theta2 ~ beta(1, 1);  // 群2の成功率にベータ(1, 1)の事前分布
  
  y1 ~ binomial(n1, theta1);  // 群1の成功数
  y2 ~ binomial(n2, theta2);  // 群2の成功数
}
generated quantities {
  real diff;  // 群1と群2の成功率の差
  diff = theta1 - theta2;
}
"""

with open('two_group_proportion.stan', 'w') as f:
    f.write(stan_code)

# CmdStanModelオブジェクトを作成
model = cmdstanpy.CmdStanModel(stan_file='two_group_proportion.stan')

# データをStanに渡す
data = {
    'n1': n1,
    'y1': y1,
    'n2': n2,
    'y2': y2
}

# サンプリング実行
fit = model.sample(data=data, chains=4, iter_sampling=2000, iter_warmup=1000)

# 結果の表示
print(fit.summary())

# 生成された成功率の差 (diff) のサンプルを取得
diff_samples = fit.stan_variable('diff')

# 95%ベイズ信用区間の計算
lower_bound = np.percentile(diff_samples, 2.5)
upper_bound = np.percentile(diff_samples, 97.5)

print(f'95% ベイズ信用区間: [{lower_bound:.3f}, {upper_bound:.3f}]')

# 群1と群2の成功率の差の分布をプロット
plt.hist(diff_samples, bins=30, density=True, alpha=0.7)
plt.axvline(lower_bound, color='red', linestyle='--', label=f'2.5%: {lower_bound:.3f}')
plt.axvline(upper_bound, color='blue', linestyle='--', label=f'97.5%: {upper_bound:.3f}')
plt.title('Difference in Proportions (theta1 - theta2)')
plt.xlabel('Difference')
plt.ylabel('Density')
plt.legend()
plt.show()

# arvizを使ってトレースプロットを描画する
az_data = az.from_cmdstanpy(fit)  # cmdstanpyの結果をArviZ形式に変換

# diff(成功率の差)のトレースプロットを表示
az.plot_trace(az_data, var_names=["diff"])
plt.show()
差の分布(および95%信用区間)と、トレースプロット