I’ve been playing around with a Stan version of the semilocal linear trend model, as found in the R package bsts. The model both automatically scales and matches bsts’s fit fairly well. Still, I’m hoping to get some feedback about:
- starting points
mu[1]andnu[1], - choice of priors (I offer my thoughts in line), and
- possible ways to eliminate the few and sporadic divergences, as the simple solution of increase adapt_delta is already used.
data {
int <lower=1> T;
vector[T] y;
}
transformed data {
real sd_y = sd(y);
}
parameters {
real<lower=0> sigma_y;
vector[T] gamma;
real<lower=0> sigma_gamma;
vector[T] zeta;
real<lower=0> sigma_zeta;
real eta;
real<lower=-1, upper=1> phi;
}
transformed parameters {
vector[T] mu;
vector[T] nu;
mu[1] = y[1] + sigma_gamma * gamma[1];
nu[1] = zeta[1];
for (t in 2:T) {
mu[t] = mu[t-1] + nu[t-1] + sigma_gamma * gamma[t];
nu[t] = eta + phi * (nu[t-1] - eta) + sigma_zeta * zeta[t];
}
}
model {
// priors
//sigma_y ~ exponential(1 / sd_y);
sigma_y ~ normal(0, 2.5 * sd_y);
gamma ~ normal(0, 1);
// sigma_gamma ~ gamma(2, 1 / sd_y);
sigma_gamma ~ normal(0, 2.5 * sd_y);
zeta ~ normal(0, 1);
// sigma_zeta ~ gamma(2, 1 / sd_y);
sigma_zeta ~ normal(0, 2.5 * sd_y);
eta ~ normal(0, sd_y);
phi ~ normal(0, 0.5);
// likelihood
y ~ normal(mu, sigma_y);
}
generated quantities {
vector[T] y_pred;
for (t in 1:T)
y_pred[t] = normal_rng(mu[t], sigma_y);
}
If you’re interested, here’s some R code to get you started. The code below compares some features from Stan and bsts fits across two data sets, one from the datasets package and one from bsts.
library(rstan)
options(mc.cores = parallel::detectCores())
rstan_options(auto_write = TRUE)
library(bsts)
sm <- stan_model('semilocal_linear_trend.stan')
## Nile
y <- as.vector(Nile)
T <- length(y)
x <- 1:T
## rsxfs
data(rsxfs)
y <- as.vector(rsxfs)
T <- length(y)
x <- 1:T
### Stan
sfit <- sampling(sm, data=list(y = y, T = T),
control=list(adapt_delta=0.99,
max_treedepth=15))
### bsts
m <- list()
m <- AddSemilocalLinearTrend(m, y=y)
bfit <- bsts(y, m, niter=2000)
### plot
plot(x, y, type='l')
lines(x, colMeans(bfit$state.contributions), col='red')
lines(x, colMeans(extract(sfit, "y_pred")$y_pred), col='blue')
plot(density(bfit$trend.slope.mean), col='red')
lines(density(extract(sfit, "eta")$eta), col='blue')
summary(bfit$trend.slope.mean)
summary(extract(sfit, "eta")$eta)
Thanks in advance for any and all comments.

