library(nimble)
## nimble version 1.0.1 is loaded.
## For more information on NIMBLE and a User Manual,
## please visit https://R-nimble.org.
##
## Note for advanced users who have written their own MCMC samplers:
## As of version 0.13.0, NIMBLE's protocol for handling posterior
## predictive nodes has changed in a way that could affect user-defined
## samplers in some situations. Please see Section 15.5.1 of the User Manual.
##
## 次のパッケージを付け加えます: 'nimble'
## 以下のオブジェクトは 'package:stats' からマスクされています:
##
## simulate
library(coda)
library(posterior)
## This is posterior version 1.4.1
##
## 次のパッケージを付け加えます: 'posterior'
## 以下のオブジェクトは 'package:stats' からマスクされています:
##
## mad, sd, var
## 以下のオブジェクトは 'package:base' からマスクされています:
##
## %in%, match
library(stringr)
library(ggplot2)
set.seed(123)
久保さんの『データ解析のための統計モデリング入門』11章「空間構造のある階層ベイズモデル」にある、条件付き自己回帰 (CAR) モデルのあてはめを、NIMBLEで再現してみます。
モデルの詳細は、同書をご覧ください。
準備
まず、使用するパッケージの読み込みと疑似乱数系列の固定です。
データ
同書のサポートページからデータをダウンロードします。
# data
<- "https://kuboweb.github.io/-kubo/stat/iwanamibook/fig/spatial/Y.RData"
data_url <- "Y.RData"
data_file
if (!file.exists(data_file)) {
download.file(data_url, data_file, "auto")
}
load(data_file)
データの確認
データを確認します。1〜50の番号がついた場所が1次元で並んでいて、各場所で、ある生物の個体数が得られているというデータです。
<- length(Y)
N_site <- ggplot(data.frame(location = seq_len(N_site), y = Y)) +
p geom_point(aes(x = location, y = y)) +
ylim(0, 25) +
labs(x = expression(paste("Location ", italic(j))),
y = expression(paste("Population ", italic(y)[italic(j)]))) +
theme_bw(base_family = "Helvetica")
print(p)
次に、空間自己相関の計算につかう数値を用意します。各場所(1〜N_site
)について順番に、adj
に隣接する場所の番号、weights
に重み(ここではすべて1)、num
に隣接する場所の数を入れておきます。
<- c(2,
adj sapply(2:(N_site - 1), function(i) c(i - 1, i + 1)) |> c(),
- 1)
N_site <- rep(1, length(adj))
weights <- c(1, rep(2, N_site - 2), 1) num
モデル
NIMBLEのモデルです。CARモデルにはいくつかアルゴリズムがありますが、ここではintrinsic Gaussian CARモデルを使用しています。WinBUGSではcar.normal
という名前でしたが、NIMBLEではdcar_normal
という名前になっています。
<- nimbleCode({
car_code for (j in 1:N_site) {
~ dpois(mean[j])
Y[j] log(mean[j]) <- beta + r[j]
}
1:N_site] ~ dcar_normal(adj[1:L], weights[1:L], num[1:N_site],
r[zero_mean = 1)
tau, ~ dnorm(0, 1.0e-4)
beta <- 1 / (s * s)
tau ~ dunif(0, 1.0e+4)
s })
初期値設定のための関数を定義します。
<- function() {
init_fun list(beta = runif(1, -2, 2),
s = runif(1, 0, 2),
r = runif(N_site, -2, 2))
}
MCMCの実行です。
<- nimbleMCMC(car_code,
car_mcmc constants = list(N_site = N_site, L = length(adj),
adj = adj, weights = weights,
num = num),
data = list(Y = Y),
inits = init_fun,
monitors = c("beta", "s", "mean"),
niter = 3000, nburnin = 1000,
nchains = 3,
samplesAsCodaMCMC = TRUE)
## Defining model
## Building model
## Setting data and initial values
## Running calculate on model
## [Note] Any error reports that follow may simply reflect missing values in model variables.
## Checking model sizes and dimensions
## Checking model calculations
## Compiling
## [Note] This may take a minute.
## [Note] Use 'showCompilerOutput = TRUE' to see C++ compilation details.
## running chain 1...
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## running chain 2...
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
## running chain 3...
## |-------------|-------------|-------------|-------------|
## |-------------------------------------------------------|
結果
結果をposterior
パッケージのdraws_df
形式に変換して、要約をcar_summary
に格納します。beta
とs
について値を表示します。
<- car_mcmc |>
car_summary as_draws() |>
summarise_draws()
|>
car_summary ::filter(variable %in% c("beta", "s"))
dplyr## # A tibble: 2 × 10
## variable mean median sd mad q5 q95 rhat ess_bulk ess_tail
## <chr> <num> <num> <num> <num> <num> <num> <num> <num> <num>
## 1 beta 2.27 2.27 0.0492 0.0523 2.19 2.35 1.00 437. 786.
## 2 s 0.229 0.225 0.0483 0.0476 0.155 0.314 1.02 153. 399.
Yの期待値(mean
)の事後分布の中央値および5%, 95%分位点を取り出したものに、場所の番号の列を加えます。
<- car_summary |>
mean_summary ::filter(str_starts(variable, "mean")) |>
dplyr::select(median, q5, q95) |>
dplyrcbind(location = 1:N_site)
プロット
元の図に、期待値の事後分布の中央値および90%区間を重ねます。
+
p geom_ribbon(data = mean_summary,
mapping = aes(x = location,
ymin = q5,
ymax = q95),
alpha = 0.5) +
geom_line(data = mean_summary,
mapping = aes(x = location, y = median))