I am fitting a simple, one-factor latent variable model in Stan, comparing the results to the output of lavaan, but am running into problems estimating models with different identification constraints. In particular, setting the latent variable to be a unit normal and estimating all factor loadings and intercepts.
Consider J measured variables y_{ij} for instances i = 1 ... N and variables j = 1 ... J, each with their own intercept parameter \alpha_j and factor loading \beta_j on latent variable x:
y_{ij} = \alpha_j + \beta_j * x_i
where x is normally distributed:
x_i \sim N(\mu_x, \sigma_x)
The residual covariances are assumed to be zero between the y_j.
The most common constraint to ensure identification is to fix one of the \beta_j to 1, fix the location of the latent variable to 0, and estimate the variance of the latent variable. I have implemented this in Stan, and it works well:
data{
int<lower=0> N;
int<lower=0> J;
matrix[N, J] y;
}
parameters{
vector[J] alpha;
vector[J-1] beta;
vector<lower=0>[J] sigma;
vector[N] x;
real<lower=0> x_sigma;
}
transformed parameters{
// the fixed parameter
real beta_fix[J];
beta_fix[1] = 1;
for(j in 1:J-1){
beta_fix[j+1] = beta[j];
}
}
model{
matrix[N,J] mu;
x_sigma ~ normal(0, 1);
alpha ~ normal(0, 10);
beta ~ normal(0, 1);
sigma ~ normal(0, 1);
// latent variable
x ~ normal(0, x_sigma);
for(i in 1:N){
for(j in 1:J){
mu[i,j] = alpha[j] + beta_fix[j] * x[i];
y[i,j] ~ normal(mu[i,j], sigma[j]);
}
}
}
Running this model using some data from the lavaan package using both lavaan and Stan:
require(lavaan)
data("HolzingerSwineford1939")
# lavaan model
HS.model <- 'visual =~ x1 + x2 + x3'
lavaan_fit1 <- cfa(HS.model, data=HolzingerSwineford1939, meanstructure=TRUE)
summary(lavaan_fit1)
# the Stan model
y <- as.matrix(HolzingerSwineford1939[,7:9])
N <- dim(y)[1]
J <- dim(y)[2]
stan_data <- list(
y = y, N = N, J = J
)
# fixed indicator/beta coefficient model
stan_fit_ff <- stan(file = "Stan-LV-fixed-indicator.stan",
data = stan_data)
print(stan_fit_ff, pars=c("alpha","beta","sigma","x_sigma"))
A different parameterization is fix both the latent variableâs location to 0 and scale 1, and estimate all the indicator coefficients.
I have tried implementing this is Stan but the \beta_j coefficients very infrequently converge, with effective sample sizes usually of 2. Sometimes the chains converge and I get identical estimates to lavaan. The model code and R code to run this model is below.
data{
int<lower=0> N;
int<lower=0> J;
matrix[N, J] y;
}
parameters{
vector[J] alpha;
vector[J] beta;
vector<lower=0>[J] sigma;
vector[N] x;
}
transformed parameters{
// no fixed parameters
}
model{
matrix[N,J] mu;
alpha ~ normal(0, 10);
beta ~ normal(0, 1);
sigma ~ normal(0, 1);
// latent variable
x ~ normal(0, 1);
for(i in 1:N){
for(j in 1:J){
mu[i,j] = alpha[j] + beta[j] * x[i];
y[i,j] ~ normal(mu[i,j], sigma[j]);
}
}
}
require(lavaan)
data("HolzingerSwineford1939")
# lavaan model
HS.model <- 'visual =~ x1 + x2 + x3'
lavaan_fit2 <- cfa(HS.model, data=HolzingerSwineford1939, meanstructure=TRUE, std.lv=TRUE)
summary(lavaan_fit2)
# the Stan model
y <- as.matrix(HolzingerSwineford1939[,7:9])
N <- dim(y)[1]
J <- dim(y)[2]
stan_data <- list(
y = y, N = N, J = J
)
# standardized latent variable
stan_fit_std <- stan(file = "Stan-LV-std.stan",
data = stan_data)
print(stan_fit_std, pars=c("alpha","beta","sigma"))
Does anyone know why the second model is not converging well, and what I could do about it?
Thanks for your help!