I am interested in fitting a latent variable model to a set of data. I have played with the priors quite a bit and made them very tight, and have adjusted the delta and treedepth, and increased iterations to a high number, but I am not having any luck with convergence. If anyone can help me take a look at the model and see if I have specified it incorrectly, I would greatly appreciate it. Or is there something else I can do to the priors to help convergence?
The dataset here was collected to investigate whether there is any systematic bias or differences in variability in the weight (in the dataset this is called total weight or TW
) measurements recorded by three different machines (the machines are identified as GAC
, Vol
, and Perten
). There are about 650 samples (each sample has a unique combination of Plot:Trial:Year
) that were each measured nine times, three times by each of the three machines. I tried to model this as each of those nine readings being an indication of a latent variable, the true weight TWtrue
of the sample. Each machine was allowed to have its own sigma
parameter to determine whether any of the machines gives more variable readings. A random intercept was fit for each sample as (1 | Plot:Trial:Year)
.
Here is a DAG of the model.
The data.table
looks like this. Rep
is just an identifier, so Rep 1 for one machine is not especially related to Rep 1 from another machine. The first three rows here just represent nine readings of the same sample, three times each on each of the three machines.
dat_wide
Trial Year Plot Rep GAC Perten Vol
1: H6 2020 101 1 55.8 56.3 56.3
2: H6 2020 101 2 55.8 56.1 56.0
3: H6 2020 101 3 55.8 56.9 56.2
4: H6 2020 102 1 56.3 57.2 56.3
5: H6 2020 102 2 56.3 57.4 56.5
---
1933: U8 2020 314 2 57.0 56.1 54.9
1934: U8 2020 314 3 57.0 56.1 54.9
1935: U8 2020 315 1 54.4 55.5 54.7
1936: U8 2020 315 2 54.4 55.6 54.5
1937: U8 2020 315 3 54.4 55.6 54.4
Here I create a column of NA
s for the latent variable then define the different components of the model formula. The TWtrue
variable predicts each of the three observed variables, is coded as missing, and has a random intercept for each sample.
dat_wide[, TWtrue := as.numeric(NA)]
bf_gac <- bf(GAC ~ mi(TWtrue))
bf_vol <- bf(Vol ~ mi(TWtrue))
bf_per <- bf(Perten ~ mi(TWtrue))
bf_tw <- bf(TWtrue | mi() ~ 0 + (1|Plot:Trial:Year))
Here are priors. I set the prior for each machine’s intercept to be centered around the overall mean of that machine, and the prior for the slopes of each machine to be around 1 because we would not expect a large difference from a slope of 1.
overall_means <- dat[, .(TW = mean(TW, na.rm = TRUE)), by = Machine]
stanvars <- stanvar(overall_means$TW[1], 'mean_gac') +
stanvar(overall_means$TW[2], 'mean_per') +
stanvar(overall_means$TW[3], 'mean_vol')
latent_model_priors <- c(
prior(normal(mean_gac, 1), class = Intercept, resp = GAC),
prior(normal(mean_per, 1), class = Intercept, resp = Perten),
prior(normal(mean_vol, 1), class = Intercept, resp = Vol),
prior(normal(1, 0.25), class = b, resp = GAC),
prior(normal(1, 0.25), class = b, resp = Perten),
prior(normal(1, 0.25), class = b, resp = Vol),
prior(gamma(5, 5), class = sigma, resp = GAC),
prior(gamma(5, 5), class = sigma, resp = Perten),
prior(gamma(5, 5), class = sigma, resp = Vol),
prior(gamma(2, 5), class = sigma, resp = TWtrue)
)
Here are two versions of the model, one with and one without residual correlation. I was not really sure which is more appropriate. Any guidance on that would also be helpful. Neither of these models converge, and they take a very long time to run on this modestly sized dataset. Thanks in advance for any help.
fit_latent <- brm(bf_gac + bf_vol + bf_per + bf_tw + set_rescor(TRUE), data = dat_wide,
prior = latent_model_priors,
chains = 4, iter = 10000, warmup = 7500, seed = 91919, stanvars = stanvars,
control = list(adapt_delta = 0.95, max_treedepth = 20))
fit_latent_norescor <- brm(bf_gac + bf_vol + bf_per + bf_tw + set_rescor(FALSE), data = dat_wide,
prior = latent_model_priors,
chains = 4, iter = 10000, warmup = 7500, seed = 19191, stanvars = stanvars,
control = list(adapt_delta = 0.95, max_treedepth = 20))