Hi!
I started by trying to replicate the CausalImpact bayesian state-space modeling package in Stan. I think I got it working pretty well, the model code is here (thanks mostly to another post on this board). Also attaching an image comparing the package result to my own. T is the total number of time steps, T0 is the time of intervention.
data {
int<lower=2> T;
int<lower=1> T0;
int<lower=1> N;
matrix[T, N] X; // correlated time series
vector[T] y; // intervention time series
}
parameters {
vector[T] u_err; //Slope innovation
vector[T] v_err; //Level innovation
vector[N] beta; // correlated time series coefficients
real<lower=0> s_obs;
real<lower=0> s_slope;
real<lower=0> s_level;
}
transformed parameters {
vector[T0] u; //Level
vector[T0] v; //Slope
u[1] = u_err[1];
v[1] = v_err[1];
for (t in 2:T0) {
u[t] = u[t-1] + v[t-1] + s_level * u_err[t];
v[t] = v[t-1] + s_slope * v_err[t];
}
}
model {
u_err ~ normal(0,1);
v_err ~ normal(0,1);
beta ~ normal(0, 1);
s_obs ~ normal(0, 5);
s_slope ~ normal(0, 0.1);
s_level ~ normal(0, 0.1);
y[1:T0] ~ normal(u + X[1:T0, :]*beta, s_obs);
}
generated quantities {
vector[T] y_rep; // predicted time series without intervention
vector[T-T0] u_rep;
vector[T-T0] v_rep;
for (t in 1:T0) {
y_rep[t] = normal_rng(u[t] + X[t, :]*beta, s_obs);
}
u_rep[1] = u[T0] + v[T0] + s_level*u_err[T0];
v_rep[1] = v[T0] + s_slope * v_err[T0];
y_rep[T0+1] = normal_rng(u_rep[1] + X[T0+1, :]*beta, s_obs);
for (t in 2:T-T0) {
u_rep[t] = u_rep[t-1] + v_rep[t-1] + s_level * u_err[t+T0];
v_rep[t] = v_rep[t-1] + s_slope * v_err[t+T0];
y_rep[t+T0] = normal_rng(u_rep[t] + X[t+T0, :]*beta, s_obs);
}
}
However, what I want to do next is make a hierarchical model across multiple time series-interventions. It gets messy for two reasons:
- The time series don’t all have the same lengths before/after intervention. Aligning things in Stan could get messy but I want to use as much pre-intervention data as possible to inform the coefficients beta.
- I’m estimating the effect indirectly, by subtracting the posterior samples of y_rep from observed y. Maybe there’s a better way to do this in the model block but I’m not sure how, I could easily adapt the generated quantities to handle that.
So my questions are two:
- If I decide to handle the messy non-aligned indexing in Stan, is there a way to measure the benefits in the model block (y[T0:T] - y_rep[T0:T]). If so, I think I know how to put a hierarchical model on top of that.
- If the above doesn’t work, can I use the posterior samples as data for a second model? I couldn’t find anything about this approach on here, in theory I don’t see why this wouldn’t work. If it’s possible, someone must have done it before so any pointers on how to do it well?
Thanks for any help! I’m still fairly new to Stan so hopefully this approach and my questions make sense.!