I am not sure how to calculate the pointwise log-likelihood – required to use loo – for a multilevel model with measurement error and identifiability hacks.
Let’s consider the following varying intercept model, with measurement error on the outcome y, and “postsweeping of random effects” to ensure identifiability of the intercepts (see solution 4 in Ogle & Barber, 2020):
I have boldly tried the following Stan code, but I don’t really know what I am doing with the _lpdf
so I thought I would double-check here…
data {
int<lower=0> N; // number of observations
int<lower=0> G; // number of groups
array[N] int<lower=1> group; // vector of groups
vector[N] y_obs; // observed outcome
vector[N] x; // predictor
real y_err; // measurement error on y_obs
}
parameters {
real alpha0; // global intercept
vector[G] alpha; // group intercepts
real beta; // slope
real<lower=0> sigma_alpha; // sd of group intercepts
real<lower=0> sigma; // sd of true outcome
vector[N] y_true; // true outcome
}
model {
// model for y_true
// adaptive prior
alpha ~ normal(0, sigma_alpha); // non-identifiable group intercepts
// hyper-prior
sigma_alpha ~ exponential(1);
// other priors
alpha0 ~ std_normal(); // non-identifiable global intercept
beta ~ std_normal();
sigma ~ exponential(1);
// likelihood
y_true ~ normal(alpha0 + alpha[group] + beta * x, sigma);
// model for y_obs
y_obs ~ normal(y_true, y_err);
}
generated quantities {
// identifiable parameters ("postsweeping of random effects", i.e., solution 4 from Ogle & Barber, 2020)
real alpha_bar = mean(alpha);
vector[G] alpha_star = alpha - alpha_bar; // identifiable group intercept
real alpha0_star = alpha0 + alpha_bar; // identifiable global intercept
// posterior predictive distribution for replications y_obs_rep of the original data set y_obs given model parameters
array[N] real y_true_rep_star = normal_rng(alpha0_star + alpha_star[group] + beta * x, sigma);
array[N] real y_obs_rep_star = normal_rng(y_true_rep_star, y_err);
// pointwise log-likelihood
vector[N] yt;
vector[N] log_lik;
for (i in 1:N) {
yt[i] = normal_lpdf(y_true[i] | alpha0_star + alpha_star[group[i]] + beta * x[i], sigma);
log_lik[i] = normal_lpdf(y_obs[i] | yt[i], y_err);
}
}