Frequently Asked Questions

1. What’s the difference between a multiple-membership model and a conventional multilevel model?

In a conventional hierarchical multilevel model, each lower-level unit belongs to exactly one higher-level unit (e.g., students nested in schools). In a multiple-membership model (MMMM), lower-level units can belong to multiple higher-level units simultaneously, or alternatively, higher-level outcomes can be influenced by multiple lower-level units.

For example:

The MMMM accounts for this complex membership structure by weighting the contributions of each lower-level unit, allowing researchers to model how multiple units jointly shape higher-level outcomes.

2. What’s the difference between a conventional MMMM and the extended MMMM implemented in bml?

The conventional MMMM (as implemented in MLwiN, brms, or other software) uses fixed, pre-specified weights to aggregate lower-level effects. For instance, you might use equal weights (1/n) or weights based on time spent in each context.

The extended MMMM in bml allows you to:

  1. Parameterize the weight function: Instead of fixing weights, you can specify a functional form for weights (e.g., w ~ 1/n^exp(b*X)) and estimate the parameters that determine how lower-level units are aggregated.

  2. Test alternative aggregation mechanisms: Compare different weighting schemes (equal weights, proportional weights, functions of covariates) to determine which best fits the data.

  3. Endogenize weight matrices: Rather than imposing spatial or network weights externally, let the data determine connection strengths as functions of covariates.

This flexibility enables researchers to explicitly model the micro-to-macro link — how lower-level characteristics aggregate to produce higher-level outcomes.

3. When should I use bml instead of other multilevel modeling packages?

Use bml when:

For standard hierarchical models without multiple membership, packages like lme4, brms, or MCMCglmm will be more efficient. For conventional MMMMs with fixed weights, brms or MLwiN are excellent alternatives.

4. What outcome types and distributions does bml support?

bml supports a variety of outcome distributions commonly used in social science research:

You can also specify hierarchical random effects (hm() blocks) in addition to multiple-membership structures, allowing for hierarchically nested and cross-classified designs.

5. How do I specify the weight function, and what are the c and ar parameters?

The weight function is specified in the fn() container within an mm() block:

mm(
  id = id(member_id, group_id),
  vars = vars(X),
  fn = fn(w ~ 1/n, c = TRUE),
  RE = TRUE,
  ar = FALSE
)

Weight function components:

Important: Only one mm() block can have RE = TRUE in a given model.

6. How do I fix parameters to known values?

There are two ways to fix parameters in bml, depending on where in the model they appear.

Main equation and hm() blocks: Using fix()

Use the fix() helper inside vars() to hold a coefficient at a specified value rather than estimating it. This works both in the main equation and in hm() blocks.

Main equation:

# Fix the coefficient of 'exposure' to 1 (i.e., use as an offset)
m <- bml(
  y ~ 1 + fix(exposure, 1) + x1 + x2,
  family = "Gaussian",
  data = dat
)

This is equivalent to adding exposure as a predictor but constraining its coefficient to 1 instead of estimating it. This is useful for offsets or when prior theory dictates a specific coefficient value.

In hm() blocks:

m <- bml(
  y ~ 1 + x1 +
    mm(id = id(pid, gid), fn = fn(w ~ 1/n), RE = TRUE) +
    hm(id = id(cid), vars = vars(fix(investiture, 0.5) + gdp), type = "FE"),
  family = "Gaussian",
  data   = coalgov
)

In mm() blocks:

m <- bml(
  Surv(dur_wkb, event_wkb) ~ 1 + majority +
    mm(
      id   = id(pid, gid),
      vars = vars(fix(cohesion, 1) + finance),
      fn   = fn(w ~ 1/n, c = TRUE),
      RE   = TRUE
    ),
  family = "Weibull",
  data   = coalgov
)

Here, the coefficient of cohesion is fixed at 1 while finance is freely estimated.

Weight function fn(): Omitting parameters

In the weight function specified via fn(), you fix weights by simply not including any free parameters (b0, b1, …) in the formula. When no parameters appear, the weight function is treated as a known, fixed transformation.

# Fixed equal weights (no parameters to estimate)
fn(w ~ 1/n, c = TRUE)

# Fixed weights proportional to seat share (no parameters to estimate)
fn(w ~ pseat, c = TRUE)

Compare this with weight functions that include free parameters:

# Estimable: b is estimated from data
fn(w ~ 1/n^exp(b * x), c = TRUE)

# Estimable: b0 is estimated from data
fn(w ~ 1 / (1 + (n - 1) * exp(-b0)), c = FALSE)

The key distinction: if the fn() formula contains b, b0, b1, etc., these are estimated. If the formula contains only data variables and constants (like n, pseat, 1), the weights are fixed.

7. I get “Error in node w.1[…]: Invalid parent values” — what does this mean?

This error occurs when JAGS cannot evaluate the weight function for a particular observation because the computed weight is numerically invalid (e.g., NaN, Inf, or a value outside the domain of a downstream function). It most commonly arises with parameterized weight functions during the initialization phase.

Why it happens: Weight function parameters (b0, b1, …) are given vague priors by default (dnorm(0, 0.0001) in JAGS precision, which corresponds to SD = 100). When JAGS initializes the MCMC chains, it may draw extreme starting values (e.g., b0 = 80). For weight functions involving nonlinear transformations like ilogit() or exp(), extreme parameter values can cause numerical issues downstream — even if the weight function itself is mathematically well-defined, the resulting weights may produce overflow in the likelihood (e.g., exp(-mu * shape) in the Weibull model).

Built-in safeguard: bml initializes all weight parameters at 0 by default. This ensures numerically stable starting values (e.g., ilogit(0) = 0.5). However, if the error persists or occurs during sampling (not just initialization), consider the following steps.

How to fix it:

  1. Use more informative priors. Narrow the prior spread for weight parameters so that the sampler stays in a numerically stable region:

    m <- bml(
      ...,
      priors = list(
        "b.w.1[1] ~ dnorm(0, 1)",   # SD = 1 instead of 100
        "b.w.1[2] ~ dnorm(0, 1)"
      )
    )

    This is especially important for parameters inside ilogit(), exp(), or other functions that saturate or explode at extreme inputs.

  2. Ensure the weight function is bounded. Unbounded weight functions can produce extreme values that destabilize the likelihood. Common strategies:

    • Use ilogit() to bound weights between 0 and 1: fn(w ~ ilogit(b0 + b1 * x), c = TRUE)
    • Use exp() carefully — it grows rapidly, so pair it with constraints like c = TRUE (normalization) or wrap the argument: fn(w ~ exp(b1 * x), c = TRUE) where x is standardized
  3. Standardize covariates in the weight function. If a weight variable has a large range (e.g., income in thousands), the product b1 * x can easily overflow. Standardize such variables before including them in fn().

  4. Supply explicit initial values. If the default initialization at 0 doesn’t work for your model, provide custom starting values:

    m <- bml(
      ...,
      inits = list("b.w.1" = c(0.5, -0.1))
    )
  5. Re-run the model. Since the error can be seed-dependent (different chains draw different initial values), simply re-running may resolve it. However, this indicates a fragile parameterization — consider steps 1–3 for a robust solution.