简体   繁体   中英

Obtaining random-effects matrices from a mixed model

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)

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 aa 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 eg constrain the relationship between entries).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM