-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested random intercepts? #406
Comments
The nesting syntax is just a convenience as far as I know. It's useful if subgroup IDs are not unique across groups. But you can make those subgroup IDs unique. I believe you can always fit the same model by recoding the IDs. E.g. library(dplyr)
set.seed(99)
d <- tibble::tibble(
frog_dens = rlnorm(100),
vegetation = rnorm(100),
pond = gl(25, 4), # generates factor levels
transect = rep(gl(2, 2), 25))
d <- d |> mutate(transect2 = gl(50, 2))
d
#> # A tibble: 100 × 5
#> frog_dens vegetation pond transect transect2
#> <dbl> <dbl> <fct> <fct> <fct>
#> 1 1.24 -1.53 1 1 1
#> 2 1.62 -0.501 1 1 1
#> 3 1.09 -1.21 1 2 2
#> 4 1.56 -0.630 1 2 2
#> 5 0.696 -1.45 2 1 3
#> 6 1.13 -0.167 2 1 3
#> 7 0.422 1.59 2 2 4
#> 8 1.63 -0.230 2 2 4
#> 9 0.695 -0.573 3 1 5
#> 10 0.274 0.563 3 1 5
#> # ℹ 90 more rows
(m1 <- lmer(log(frog_dens) ~ vegetation + (1 | pond/transect), data = d))
#> Linear mixed model fit by REML ['lmerMod']
#> Formula: log(frog_dens) ~ vegetation + (1 | pond/transect)
#> Data: d
#> REML criterion at convergence: 265.1362
#> Random effects:
#> Groups Name Std.Dev.
#> transect:pond (Intercept) 0.2107
#> pond (Intercept) 0.3100
#> Residual 0.8243
#> Number of obs: 100, groups: transect:pond, 50; pond, 25
#> Fixed Effects:
#> (Intercept) vegetation
#> -0.09739 0.07563
(m2 <- lmer(log(frog_dens) ~ vegetation + (1 | pond) + (1 | pond:transect), data = d))
#> Linear mixed model fit by REML ['lmerMod']
#> Formula: log(frog_dens) ~ vegetation + (1 | pond) + (1 | pond:transect)
#> Data: d
#> REML criterion at convergence: 265.1362
#> Random effects:
#> Groups Name Std.Dev.
#> pond:transect (Intercept) 0.2107
#> pond (Intercept) 0.3100
#> Residual 0.8243
#> Number of obs: 100, groups: pond:transect, 50; pond, 25
#> Fixed Effects:
#> (Intercept) vegetation
#> -0.09739 0.07563
(m3 <- lmer(log(frog_dens) ~ vegetation + (1 | pond) + (1 | transect2), data = d))
#> Linear mixed model fit by REML ['lmerMod']
#> Formula: log(frog_dens) ~ vegetation + (1 | pond) + (1 | transect2)
#> Data: d
#> REML criterion at convergence: 265.1362
#> Random effects:
#> Groups Name Std.Dev.
#> transect2 (Intercept) 0.2107
#> pond (Intercept) 0.3100
#> Residual 0.8243
#> Number of obs: 100, groups: transect2, 50; pond, 25
#> Fixed Effects:
#> (Intercept) vegetation
#> -0.09739 0.07563 Created on 2025-02-18 with reprex v2.1.1.9000 On a related topic, we have random slopes working in a branch and should merge into main soon. I'm not sure if we get the nested syntax for free in that branch. |
Thanks for getting back to me so quickly! I'm not sure if you were identifying my factor formatting or random intercept syntax as the focal issue... I should have also mentioned that the alternative syntax for a nested intercept fails. But, I took your example and made fake coordinates so I could put it into a library(tidyverse)
library(sdmTMB)
d <- tibble::tibble(
x = runif(100, 70, 82),
y = runif(100, 120, 150),
frog_dens = rlnorm(100),
vegetation = rnorm(100),
pond = gl(25, 4), # generates factor levels
transect = rep(gl(2, 2), 25))
d <- d |> mutate(transect2 = gl(50, 2))
mesh <- make_mesh(d, c("x", "y"), n_knots = 85); plot(mesh)
m1 <- sdmTMB(log(frog_dens) ~ vegetation + (1 | pond/transect), mesh = mesh, data = d)
#> Error: Random effect group column `transect:pond` is not a factor.
m2 <- sdmTMB(log(frog_dens) ~ vegetation + (1 | pond) + (1 | pond:transect), mesh = mesh, data = d)
#> Error: Random effect group column `transect:pond` is not a factor.
m3 <- sdmTMB(log(frog_dens) ~ vegetation + (1 | pond) + (1 | transect2), mesh = mesh, data = d) Any clarification about what's happening on my end would be great! Best, -Alex. |
It's sort of both. A given factor coding requires a given random effect grouping syntax.
You could think of it as a workaround to the identical model. The nested random effect syntax is just a convenience you can use if your random effects are coded as:
instead of:
I.e., the subgroups don't have unique IDs across groups. A quick way to fix this would be to paste the group and subgroup IDs together into a new unique subgroup ID. That's what the So, these are all identical models: set.seed(99)
d <- tibble::tibble(
x = runif(100, 70, 82),
y = runif(100, 120, 150),
frog_dens = rlnorm(100),
vegetation = rnorm(100),
pond = gl(25, 4), # generates factor levels
transect = rep(gl(2, 2), 25))
d <- d |> dplyr::mutate(transect2 = gl(50, 2))
# all identical models:
m1 <- glmmTMB::glmmTMB(log(frog_dens) ~ vegetation + (1 | pond/transect), data = d)
m2 <- glmmTMB::glmmTMB(log(frog_dens) ~ vegetation + (1 | pond) + (1 | transect2), data = d)
m_sdmTMB <- sdmTMB::sdmTMB(log(frog_dens) ~ vegetation + (1 | pond) + (1 | transect2), spatial = "off", data = d)
logLik(m1)
#> 'log Lik.' -146.6231 (df=5)
logLik(m2)
#> 'log Lik.' -146.6231 (df=5)
logLik(m_sdmTMB)
#> 'log Lik.' -146.6231 (df=5) Created on 2025-02-18 with reprex v2.1.1.9000 So if you want a 'nested' random intercept in sdmTMB, just make sure to code your subgroups as unique. |
Thank you for spelling this out for me! So would this be an example of using "natural" versus "implicit nesting" notation--in which the subgroupings is the only thing affecting the interaction variance? E.g. Schielzeth & Nakagawa, 2012. Also, apologies for my misleading example--my real data do indeed have unique subgroupings. I hadn't considered making them unique in the example, as I assumed the issue arose elsewhere. |
Hi sdmTMB team,
I'm curious if it is possible to use nested random intercepts. Below I create a nested grouping variable, made up of
group
andsite
, based on rounded coordinates. However, I can only implement them as crossed random intercepts, instead of nested ones:An error is thrown indicating that it recognizes the syntax of the nested term, but it is looking for a single column for the data?
Any help would be appreciated.
-Alex.
The text was updated successfully, but these errors were encountered: