library(TMB)
library(ggplot2)
library(tmbstan)
## 要求されたパッケージ rstan をロード中です
## 要求されたパッケージ StanHeaders をロード中です
##
## rstan version 2.32.6 (Stan version 2.32.2)
## For execution on a local, multicore CPU with excess RAM we recommend calling
## options(mc.cores = parallel::detectCores()).
## To avoid recompilation of unchanged Stan programs, we recommend calling
## rstan_options(auto_write = TRUE)
## For within-chain threading using `reduce_sum()` or `map_rect()` Stan functions,
## change `threads_per_chain` option:
## rstan_options(threads_per_chain = 1)
set.seed(123)
TMBでは、負の対数尤度を最小化することで最尤推定値を得ますが、TMBのオブジェクトを利用してMCMCのサンプリングをおこなうtmbstanというパッケージがあったので、ためしてみました。
準備
「TMBによる混合効果モデルのあてはめ」で使用したデータとTMBのモデルを再利用します。
まずはライブラリの読み込みと擬似乱数系列の固定です。
データ
ゼロ過剰ポアソン分布にしたがい、群ごとの変量効果のあるデータです。
<- 400
N <- 10
N_group <- rep(1:N_group, each = N / N_group)
group <- 0.3
p <- -1
alpha <- 0.8
beta <- -1.6 # sigma = 0.202
log_sigma <- rnorm(N_group, 0, exp(log_sigma))
ranef
<- runif(N, 0, 5)
x <- rbinom(N, 1, 1 - p) *
y rpois(N, exp(alpha + beta * x + ranef[group]))
<- data.frame(x = x, y = y, group = group)
example
ggplot(example, aes(x = x, y = y)) +
geom_point()
モデル
TMBのC++のコードです。これも「TMBによる混合効果モデルのあてはめ」のものとおなじです。
zipmix.cpp
// Zero-Inflated Poisson
#include <TMB.hpp>
template<class Type>
Type objective_function<Type>::operator() ()
{
DATA_VECTOR(Y);
DATA_VECTOR(X);
DATA_IVECTOR(group);
PARAMETER(p);
PARAMETER(alpha);
PARAMETER(beta);
PARAMETER_VECTOR(epsilon);
PARAMETER(log_sigma);
Type lp = 0;
lp += -sum(dnorm(epsilon, Type(0.0), exp(log_sigma), true));
for (int i = 0; i < Y.size(); i++) {
Type lambda = exp(alpha + beta * X(i) + epsilon(group(i)));
lp += -dzipois(Y(i), lambda, p, true);
}
return lp;
}
コンパイルと最適化
モデルをコンパイルして、できたライブラリをロードし、最適化をおこないます。ここまでは前の記事と同じです。
<- "zipmix"
model_name file.path("models", paste(model_name, "cpp", sep = ".")) |>
compile()
file.path("models", dynlib(model_name)) |>
dyn.load()
<- list(Y = example$y, X = example$x,
data group = example$group - 1)
<- list(p = 0.5, alpha = 1, beta = 1,
parameters epsilon = rep(0, N_group), log_sigma = 0)
<- MakeADFun(data, parameters, DLL = model_name,
obj_zipmix random = "epsilon")
<- nlminb(obj_zipmix$par, obj_zipmix$fn, obj_zipmix$gr) opt_zipmix
MakeADFun
関数で、最適化関数に渡すオブジェクトを作成して、nlminb
関数で最適化します。MakeADFun
関数のrandom
引数に、モデル中の変量効果であるepsilon
を指定します。
結果
TMBによる最尤推定の結果です。
print(opt_zipmix)
## $par
## p alpha beta log_sigma
## 0.2992974 -1.0778807 0.8271015 -1.5772257
##
## $objective
## [1] 678.5374
##
## $convergence
## [1] 0
##
## $iterations
## [1] 24
##
## $evaluations
## function gradient
## 32 25
##
## $message
## [1] "relative convergence (4)"
tmbstanでMCMC
つづいて、このモデルを利用してtmbstanでMCMCのサンプリングをおこないます。tmbstanはrstanを使っており、chains
などの引数はrstan::sampling
に渡されます。また返り値はstanfit
クラスのオブジェクトになります。
<- tmbstan(obj_zipmix,
stanfit_zipmix chain = 4, iter = 5000, warmup = 1000,
cores = min(4, parallel::detectCores()))
結果の要約です。
print(stanfit_zipmix)
## Inference for Stan model: zipmix.
## 4 chains, each with iter=5000; warmup=1000; thin=1;
## post-warmup draws per chain=4000, total post-warmup draws=16000.
##
## mean se_mean sd 2.5% 25% 50% 75% 97.5% n_eff
## p 0.30 0.00 0.03 0.24 0.28 0.30 0.32 0.36 10405
## alpha -1.08 0.00 0.14 -1.35 -1.17 -1.08 -0.99 -0.82 4412
## beta 0.83 0.00 0.03 0.77 0.81 0.83 0.85 0.88 6629
## epsilon[1] -0.04 0.00 0.11 -0.25 -0.11 -0.04 0.03 0.18 5727
## epsilon[2] -0.02 0.00 0.11 -0.23 -0.09 -0.02 0.05 0.19 5516
## epsilon[3] 0.33 0.00 0.10 0.15 0.27 0.33 0.40 0.54 4677
## epsilon[4] -0.01 0.00 0.12 -0.25 -0.09 -0.02 0.06 0.22 6000
## epsilon[5] -0.05 0.00 0.12 -0.28 -0.13 -0.05 0.02 0.17 6402
## epsilon[6] 0.33 0.00 0.11 0.13 0.26 0.32 0.40 0.54 5203
## epsilon[7] 0.05 0.00 0.11 -0.16 -0.02 0.05 0.13 0.27 5521
## epsilon[8] -0.31 0.00 0.12 -0.55 -0.38 -0.30 -0.23 -0.08 6246
## epsilon[9] -0.21 0.00 0.11 -0.44 -0.29 -0.21 -0.14 0.00 6259
## epsilon[10] -0.05 0.00 0.11 -0.26 -0.12 -0.05 0.02 0.16 5333
## log_sigma -1.48 0.00 0.28 -2.00 -1.68 -1.50 -1.30 -0.91 8342
## lp__ -669.59 0.03 2.71 -675.81 -671.21 -669.24 -667.65 -665.28 6019
## Rhat
## p 1
## alpha 1
## beta 1
## epsilon[1] 1
## epsilon[2] 1
## epsilon[3] 1
## epsilon[4] 1
## epsilon[5] 1
## epsilon[6] 1
## epsilon[7] 1
## epsilon[8] 1
## epsilon[9] 1
## epsilon[10] 1
## log_sigma 1
## lp__ 1
##
## Samples were drawn using NUTS(diag_e) at Sun Sep 22 09:52:08 2024.
## For each parameter, n_eff is a crude measure of effective sample size,
## and Rhat is the potential scale reduction factor on split chains (at
## convergence, Rhat=1).
p
とalpha
の事後平均は、最尤推定値と近い値となっています。
TMBの最尤推定で使っているnlminb
関数による最適化では、局所最適にはまってしまう可能性もありそうですので、そのような場合にはMCMCによる推定が役に立ちそうです。