Some quirks of JAGS

I return to JAGS infrequently enough these days that I forget a lot of things. Do not get me wrong. I love JAGS and I think it is one of the most valuable tools in my toolbox. However administrative and professional duties often destroy any chance I might have of concentrating long enough to actually do some decent statistics.

Despite this I have been working with my colleagues and friends, Duncan Taylor and Mikkel Andersen–who has been visiting from Aalborg since February and really boosting my research, on some decent Bayesian modelling. Along the way we have encountered a few idiosyncrasies of JAGS which are probably worth documenting. I should point out that the issues here have been covered by Martyn Plummer and others on Stack Overflow and other forums, but perhaps not as directly.

Local variables

JAGS allows local variables. In fact you probably use them without realizing as loop indices. However, what it does not like is the declaration of local variables within a loop. That is

model{
  k <- 10
}

is fine, whereas

model{
  for(i in 1:10){
    k <- 10
  }
}

is not. This would be fine, except the second code snippet will yield an error which tells you that k is an unknown variable and asks you to: Either supply values for this variable with the data or define it on the left hand side of a relation. I think this error message is a bit of a head scratcher because look at your code and say “But I have defined it, and it works in R.” – do not fall into the latter mode of thinking – it’s a trap!

There are a couple of solutions to this problem. Firstly, you could do as I did and give up on having your model code readable, and just not use temporary variables like this, or, secondly, you could like the temporary variable vary with the index, like so

model{
  for(i in 1:10){
    k[i] <- 10
  }
}

Missing data / ragged arrays

JAGS cannot deal with missing covariates very well. However, it is happy enough for you to include these observations and “step over” them some how. An example of this might be a balanced experiment where some of the trials failed. As an example let us consider a simple two factorial completely randomised design where each factor only has two levels. Let the first factor have levels A and B, and the second factor have levels 1 and 2. Furthermore let there be 3 replicates for each treatment (combination of the factors). Our (frequentist) statistical model for this design would be

\(
y_{ijk}=\mu + \alpha_i + \beta_j + \gamma_{ij} + \varepsilon_{ijk},~i\in\{A,B\},j\in\{1,2\},k=1,\ldots,3,\varepsilon_{ijk}\sim N(0,\sigma^2)
\)

And we would typically programme this up in JAGS as something like this

model{
  for(i in 1:2){
    for(j in 1:2){
      for(k in 1:3){
        y[i,j,k] ~ dnorm(mu[i,j], tau)
      }
      mu[i,j] <- alpha[i] + beta[j] + gamma[i,j]
    }
  }

  for(i in 1:2){
    alpha[i] ~ dnorm(0, 0.000001)
  }

  for(j in 1:2){
    beta[j] ~ dnorm(0, 0.000001)
  }

  for(i in 1:2){
    for(j in 1:2){
      gammma[i,j] ~ dnorm(0, 0.000001)
    }
  }

  tau ~ dgamma(0.001, 0.001)
}

Implicit in this code is that y is a 2 x 2 x 3 array, and that we have a fully balanced design. Now let us assume that, for some reason, the treatments $$\tau\in\{A1,A2,B1,B2\}$$ have been replicated 2, 3, 2, 3 times respectively. We can deal with this in JAGS by creating another variable in our input data which we will call reps with reps = c(3, 2, 3, 2). This then can be accommodated in our JAGS model by

model{
  for(i in 1:2){
    for(j in 1:2){
      for(k in 1:reps[(i-1) * 2 + j]){
        y[i,j,k] ~ dnorm(mu[i,j], tau)
      }
      mu[i,j] <- alpha[i] + beta[j] + gamma[i,j]
    }
  }

y is still a 2 x 2 x 3 array, but simply has NA stored in the positions without information. It is also worth noting that ever since JAGS 4.0 the syntax for loops allows

for(v in V){

where V is a vector containing integer indices. This is very useful for irregular data.

NOTE I have not compiled the JAGS code in my second example, so please let me know if there are mistakes. This is an ongoing article and so I may update it from time to time.

Share Button

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.