Obtaining random-effects matrices from a mixed model

被刻印的时光 ゝ 提交于 2021-02-18 08:42:23

问题


In my below code, I was wondering how I can obtain the equivalent of out and Ts from an lme() object in the library(nlme)?

dat <- read.csv("https://raw.githubusercontent.com/rnorouzian/v/main/mv.l.csv")

library(lme4)

x <- lmer(value ~0 + name+ (1| School/Student), data = dat,
          control = lmerControl(check.nobs.vs.nRE= "ignore"))

    lwr <- getME(x, "lower")
    theta <- getME(x, "theta")

    out = any(theta[lwr == 0] < 1e-4)  # find this from `x1` object below
     Ts = getME(x, "Tlist")            # find this from `x1` object below


# Fitting the above model using `library(nlme)`:

library(nlme)

x1 <- lme(value ~0 + name, random = ~1| School/Student, data = dat)

回答1:


I would strongly suggest reading the docs! lme4 and nlme use inherently different methods for fitting mixed models -- lme4 uses a penalized least-squares formulation based on the lower Cholesky factor (theta) and nlme4 uses a generalized least-squares formulation that can optionally be stored as a Cholesky factor -- but their docs give you the information to get what you need from the internal representation. After that, it's up to you to do the math to convert between the representations.

If you do ?lme then there is the line

See lmeObject for the components of the fit

Then you do ?lmeObject, where you find two promising entries:

apVar
an approximate covariance matrix for the variance-covariance coefficients. If apVar = FALSE in the control values used in the call to lme, this component is NULL.

and

modelStruct an object inheriting from class lmeStruct, representing a list of mixed-effects model components, such as reStruct, corStruct, and varFunc objects.

Well, we don't actually want the var-cov coefficients, but rather the random effects matrices. So we can look at reStruct. That is a lot more flexible in nlme than lme4, but it's generally just the random effects matrices. To do anything comparable to lme4, you need to transform those to their lower Cholesky factor. Here's an example using the sleepstudy data:

> library("nlme")
> library("lme4")
> 
> data("sleepstudy")
> m_nlme <- lme(fixed=Reaction ~ 1 + Days,
+               random=~ 1 + Days | Subject,
+               data=sleepstudy,
+               method = "ML")
> m_lme4 <- lmer(Reaction ~ 1 + Days + (1 + Days|Subject),
+                data=sleepstudy,
+                REML=FALSE)
> 
> re_lme4 <- getME(m_lme4, "Tlist")$Subject
> print(re_lme4)
           [,1]      [,2]
[1,] 0.92919061 0.0000000
[2,] 0.01816575 0.2226432
> 
> re_nlme <- m_nlme$modelStruct$reStruct$Subject
> # entire covariance matrix
> print(re_nlme)
Positive definite matrix structure of class pdLogChol representing
            (Intercept)       Days
(Intercept)  0.86344433 0.01688228
Days         0.01688228 0.04990040
> # get the lower cholesky factor
> re_nlme <- t(chol(re_nlme)) # could also use pdMatrix(re_nlme, TRUE)
> print(re_nlme)
            (Intercept)      Days
(Intercept)  0.92921705 0.0000000
Days         0.01816829 0.2226439

The theta vector for lme4 is just a row-major representation of the lower triangle of the lower Cholesky factor for a given grouping variable. (For models with multiple grouping variables, you just concatenate these together.) The lower Cholesky factor is constrained to not have entries smaller than zero on the diagonal (because that would correspond to a negative variance), and otherwise not constrained. In other words, diagonal entries get a a lower bound at 0, all other entries get a lower bound at -Inf.

So, in lme4:

> re_lme4[lower.tri(re_lme4,diag = TRUE)]
[1] 0.92919061 0.01816575 0.22264321
> getME(m_lme4, "theta")
     Subject.(Intercept) Subject.Days.(Intercept)             Subject.Days 
              0.92919061               0.01816575               0.22264321 
> getME(m_lme4, "lower")
[1]    0 -Inf    0

We can implement this for nlme (not the most efficient way, but it shows how things are built up):

> lowerbd <- function(x){
+   dd <- diag(0, nrow=nrow(x))
+   dd[lower.tri(dd)] <- -Inf
+   dd[lower.tri(dd, diag=TRUE)]
+ }
> lowerbd(re_nlme)
[1]    0 -Inf    0
> lowerbd(re_lme4)
[1]    0 -Inf    0

Note that this is one spot where nlme is actually more powerful than lme4: the whole pdMatrix set of restrictions can create different lower bounds for different entries (as well as e.g. constrain the relationship between entries).



来源:https://stackoverflow.com/questions/66017374/obtaining-random-effects-matrices-from-a-mixed-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!