問題は次の通りです:
エネルギー $i = (1,2,\ldots,20)$ における粒子の個数データ \[ y = c(11,4,13,10,4,8,6,16,7,12,10,13,6,5,1,4,2,0,0,1) \] を得た。データは $y_i \sim \mathrm{Poisson}(x_i)$,$x_i = ae^{-(i-10)^2/(2 \cdot 3^2)} + be^{-i/10}$ に従うとして,$a$,$b$ の事後分布を推定したい。
Stanコードはとりあえず次のように書けます。Rのつもりで 1/18 と書くと,整数の範囲で計算して 0 になります。
// ex76.stan
data {
int n;
int y[n];
}
parameters {
real a;
real b;
}
model {
for (i in 1:n) {
real x = a * exp((-1.0/18.0)*square(i-10)) + b * exp(-0.1*i);
target += -0.5 * log(x); // Jeffreys prior
y[i] ~ poisson(x);
}
}
ベクトルをうまく使えばループをなくすことができます:
// ex76.stan
data {
int n;
int y[n];
}
transformed data {
vector[n] p;
vector[n] q;
for (i in 1:n) {
p[i] = exp((-1.0/18.0) * square(i - 10));
q[i] = exp(-0.1 * i);
}
}
parameters {
real a;
real b;
}
model {
vector[n] x = a * p + b * q;
target += -0.5 * sum(log(x)); // Jeffreys prior
y ~ poisson(x);
}
Rコードは次の通りです:
ydata = c(11,4,13,10,4,8,6,16,7,12,10,13,6,5,1,4,2,0,0,1)
data = list(n=length(ydata), y=ydata)
fit = stan("ex76.stan", data=data, iter=26000, warmup=1000)
fit
本書の図7.8を描くには次のようにします:
poissonci = function(y) {
if (y == 0) {
qgamma(c(0,0.95), 0.5)
} else {
qgamma(c(0.025,0.975), y+0.5)
}
}
ci = sapply(1:20, function(i) poissonci(ydata[i]))
plot(1:20, ydata, type="p", pch=16, xlab="", ylab="", ylim=range(ci))
arrows(1:20, ci[1,], 1:20, ci[2,], length=0.03, angle=90, code=3)
e = extract(fit)
a = median(e$a)
b = median(e$b)
f = function(x) a * exp(-(x-10)^2/(2*3^2)) + b * exp(-x/10)
curve(f, add=TRUE)