Specifying a 3-level model, with distinct prior between groups within same level

Please also provide the following information in addition to your question:

  • Operating System: Windows 10 Pro, RStudio 1.2.5033, Microsoft R Open 3.5.3
  • brms Version: 2.11.1

Hi all,

I’ve recently come across brms and keen to use it more often given its efficient stan code & the predict function. Currently running it on some spatial observations across multiple levels, and am unsure as to whether I’ve specified the syntax correctly.

In my scenario, there are a number of observations (Fines) within each county, nested under a hierarchical Region, which in turn is grouped under Country.

There is already a modelled levy amount applied that doesn’t vary across geo-locations, but I’d like to determine whether an additional loading bsaed on counties would better model the fines.

WIth a fixed loading/ intercept per each county, my current formula is specified as follows:

bf.formula.1 <- bf(
  log(Fines) ~ log(Levy) + Modifier,
  Modifier ~ (0 + counties||regions) + (0 + counties||country)
  nl = TRUE
  1. Is the above correctly modelling a fixed intecept per county, nested within region and country?

  2. If I want to specify a separate prior on different countries pending on their value (1 or 2) - how would I do that?
    e.g. Modifier in country 1 expected to be +50%: N(1.5, 0.05), where as country 2 is expceting a reduction of 20%: N(0.8, 0.05)
    I’ve read online documentation on set_prior , but can’t find any that would allow differring ones depending on its grouped value

  3. Lastly, I understand that brms can directly model a distribution’s parameter as a response e.g. mu for lognormal etc. Would that also work for custom families?

Probably quite a simple question for the users here, but would appreciate any help. Many thanks in advance!

Hey! Welcome to the Stan forum! :)

I’m no brms expert, but I used to use lme4 a bit (before switching to Stan).

Just to make sure, I understand what you want to do: I’m not 100% sure, but the the (...||...) syntax means that slopes and intercepts are not correlated. But you don’t include intercepts in the random effect specification. Am I missing something? Also, I take it that you want your model to reflect the hierarchical structure in the picture, right?

So the specification that comes to mind (ignoring the prior question for a moment) is log(Fines) ~ log(Levy) + (1 | country/region/counties ), which is the same as log(Fines) ~ log(Levy) + (1 | country ) + (1 | country:region) + (1 | country:region:county ) .

Now to your questions:

  1. I’m not sure if brms allows factor variables as “fixed effects”. Apart from that, it’s a bit hard to tell if the specification is actually nested. If the levels of the factors are defined as in the picture (everything unique) then, I think, yes, the structure is naturally hierarchical.
  2. I’m really not sure if you can set individual priors in brms. You can always generate the stan_code and change everything that you need to change in Stan. If it is just individual prior, I think this is not that bad actually. Also, when you are working on the log scale, then these prior should be more like (roughly) N(0.4, \sigma_\text{country}) for a 50% increase and N(-0.2, \sigma_\text{country}) for a 20% reduction, right?
  3. brms normally let’s you specify the linear predictor of the location parameter of a distribution. For the Lognormal that would be \mu (you can also model \sigma). Although I didn’t check this, there should be nothing stopping you from being able to do the same for custom families.

Hope this helps. :)

Hey Max - thanks for the quick reply!

On the (...||...) syntax - I thought that just means the slopes/ intercepts are not correlated with other slopes/ intercepts between groups? From p.3 here: https://journal.r-project.org/archive/2018/RJ-2018-017/RJ-2018-017.pdf

For instance, if the userwere to write (1 | g1/g2),brms will expand this to (1 | g1) + (1 | g1:g2). Instead of |, usersmay use || in grouping terms to prevent group-level correlations from being modeled.

The solution implemented inbrms(and currently unique to it) expands the | operator into |<ID>|, where <ID> can be any value. Group-level terms withthe same ID will then be modeled as correlated if they share same grouping factor(s). For instance, if the terms (x1|ID|g1) and (x2|ID|g1) appear somewhere in the same or different formulas passed to brms, they will be modeled as correlated.

So based on the above, I used the || to make sure that the fixed intercept for each county would be uncorrelated to each other. Perhaps I’ve over complicated things?

And yes - the model should reflect the hierarchical structure in the picture.

In terms of your suggested formula, the syntax makes sense uner lme4. However, looking at the same page in the doc linked above:

We propose that group can generally be split upin its terms so that, for example, (1 | g1 + g2) is expanded to (1 | g1) + (1 | g2). This is fully consistent with the way / is handled and provides a natural generalization to the existing syntax.

Would that not suggest that (1 | g1) + (1 | g2) is same as (1 | g1/g2) and (1 | g1 + g2)? Or are the latter 2 terms not equivalent? I found another post, where the hierarchical formulation seems to suggest the / operator isn’t needed. Or perhaps that was only used in the case of multi-membership at level 2?

In addition, if (1 | country/region/counties) looks at the fixed intercept + random slope for each county (relative/ differences to the intercept) nested underneath the country and region, would it not be the same as (0 + counties | country/region) with a random slope per each county category with no intercept?

With regards to my 2nd question, if I formulate as per your suggested syntax, I see the following stancodes in the model portion:

     vector[N] nlp_Modifier = X_Modifier * b_Modifier;
  // initialize non-linear predictor term
  vector[N] mu;
  for (n in 1:N) {
    // add more terms to the linear predictor
    nlp_Modifier[n] += r_1_Modifier_1[J_1[n]] * Z_1_Modifier_1[n] + r_2_Modifier_1[J_2[n]] * Z_2_Modifier_1[n] + r_3_Modifier_1[J_3[n]] * Z_3_Modifier_1[n];
  for (n in 1:N) {
    // compute non-linear predictor values
    mu[n] = log(C_1[n]) + nlp_Modifier[n];
// priors including all constants
      target += student_t_lpdf(sigma | 3, 0, 10) - 1 * student_t_lccdf(0 | 3, 0, 10);
      target += student_t_lpdf(sd_1 | 3, 0, 10) - 1 * student_t_lccdf(0 | 3, 0, 10);
      target += normal_lpdf(z_1[1] | 0, 1);
      target += student_t_lpdf(sd_2 | 3, 0, 10) - 1 * student_t_lccdf(0 | 3, 0, 10);
      target += normal_lpdf(z_2[1] | 0, 1);
      target += student_t_lpdf(sd_3 | 3, 0, 10) - 1 * student_t_lccdf(0 | 3, 0, 10);
      target += normal_lpdf(z_3[1] | 0, 1);

What would actually be needed to put a specific prior for a given group value…? I can see that the grouping value is for example stored in J_3[n], which in turn feeds the r_3_Modifier and the nlp_Modifier, but not sure how to proceed…

Hopefully once the priors are changed, I can just follow this to re-fit in brms.

Sorry for the long reply - am still getting my head around the way that brms’ syntax and its generated code work!

Thanks again - much appreciated!

1 Like

(1 | country/region/counties) is almost likely what you want. Somethign like (0 + county | region) implies one effect per county per region, which does not make sense since each county is only in a specific region (not in all regions).

Why were you using non-linear syntax in your first model? If you want to add log(levy) to your model without a regression coefficient associated with it, you can use an offset(log(Levy)) term in a linear formula.

You can use the distributional regression approach in custom families as well.


Ah that makes sense on each county mapping to 1 region only.

Would that change if the higher level has multi-membership (on another example…)? I see that you favoured the (1 | b_id) + (1 | mm(c1, c2)) rather than the / in the form of (1 | b_id/mm(c1, c2)) in this post: (Specifying multi membership on level 3 in model with errorsar structure). I also see from slide 73 https://www.barelysignificant.com/slides/RGUG2019#73 that 3-level system is modelled as (1 | study) + (1 | experiment) rather than (1 | study/ experiment) - are they equivalent?

Is there much difference in performance between the linear and non-linear syntax? I was playing with several other forms of the model that would be non-linear so kept the nl = true for convenience.

And lastly, on specifying a particular prior on a specific value of the group i.e. country 1 having a different prior to country 2, how would I change the extracted stancode above to do that?

Or is there a way to do so in brmsformula and specify them in set_prior? Something like log(Fines) ~ log(Levy) + (1 | gr(region/counties, by = country) )? https://rdrr.io/cran/brms/man/brmsformula.html

For details on brms’ multilevel syntax see https://journal.r-project.org/archive/2018/RJ-2018-017/index.html

If possible, I recommend the linear syntax as it allows more code optimization and may be faster in come cases.

If you use multilevel syntax, you cannot set different priors for country 1 and 2.