For IGF
data from nlme
library, I\'m getting this error message:
lme(conc ~ 1, data=IGF, random=~age|Lot)
Error in lme.formula(conc ~ 1
I find the other, older answer here unsatisfactory. I distinguish between cases where, statistically, age has no impact and conversely we encounter a computational error. Personally, I have made career mistakes by conflating these two cases. R has signaled the latter and I would like to dive into why that is.
The model that OP has specified is a growth model, with random slopes and intercepts. A grand intercept is included but not a grand age slope. One unsavory constraint that is imposed by fitting a random slope without addition of its "grand" term is that you are forcing the random slope to have 0 mean, which is very difficult to optimize. Marginal models indicate age does not have a statistically significant different value from 0 in the model. Furthermore adding age as a fixed effect does not remedy the problem.
> lme(conc~ age, random=~age|Lot, data=IGF)
Error in lme.formula(conc ~ age, random = ~age | Lot, data = IGF) :
nlminb problem, convergence error code = 1
message = iteration limit reached without convergence (10)
Here the error is obvious. It might be tempting to set the number of iterations up. lmeControl
has many iterative estimands. But even that doesn't work:
> fit <- lme(conc~ 1, random=~age|Lot, data=IGF,
control = lmeControl(maxIter = 1e8, msMaxIter = 1e8))
Error in lme.formula(conc ~ 1, random = ~age | Lot,
data = IGF, control = lmeControl(maxIter = 1e+08, :
nlminb problem, convergence error code = 1
message = singular convergence (7)
So it's not a precision thing, the optimizer is running out-of-bounds.
There must be key differences between the two models you have proposed fitting, and a way to diagnose the error that you have found. One simple approach is specifying a "verbose" fit for the problematic model:
> lme(conc~ 1, random=~age|Lot, data=IGF, control = lmeControl(msVerbose = TRUE))
0: 602.96050: 2.63471 4.78706 141.598
1: 602.85855: 3.09182 4.81754 141.597
2: 602.85312: 3.12199 4.97587 141.598
3: 602.83803: 3.23502 4.93514 141.598
(truncated)
48: 602.76219: 6.22172 4.81029 4211.89
49: 602.76217: 6.26814 4.81000 4425.23
50: 602.76216: 6.31630 4.80997 4638.57
50: 602.76216: 6.31630 4.80997 4638.57
The first term is the REML (I think). The second through fourth terms are the parameters to an object called lmeSt
of class lmeStructInt
, lmeStruct
, and modelStruct
. If you use Rstudio's debugger to inspect attributes of this object (the lynchpin of the problem), you'll see it is the random effects component that explodes here. coef(lmeSt)
after 50 iterations produces
reStruct.Lot1 reStruct.Lot2 reStruct.Lot3
6.316295 4.809975 4638.570586
as seen above and produces
> coef(lmeSt, unconstrained = FALSE)
reStruct.Lot.var((Intercept)) reStruct.Lot.cov(age,(Intercept))
306382.7 2567534.6
reStruct.Lot.var(age)
21531399.4
which is the same as the
Browse[1]> lmeSt$reStruct$Lot
Positive definite matrix structure of class pdLogChol representing
(Intercept) age
(Intercept) 306382.7 2567535
age 2567534.6 21531399
So it's clear the covariance of the random effects is something that's exploding here for this particular optimizer. PORT routines in nlminb
have been criticized for their uninformative errors. The text from David Gay (Bell Labs) is here http://ms.mcmaster.ca/~bolker/misc/port.pdf The PORT documentation suggests our error 7 from using a 1 billion iter max "x may have too many free components. See §5.". Rather than fix the algorithm, it behooves us to ask if there are approximate results which should generate similar outcomes. It is, for instance, easy to fit an lmList
object to come up with the random intercept and random slope variance:
> fit <- lmList(conc ~ age | Lot, data=IGF)
> cov(coef(fit))
(Intercept) age
(Intercept) 0.13763699 -0.018609973
age -0.01860997 0.003435819
although ideally these would be weighted by their respective precision weights:
To use the nlme
package I note that unconstrained optimization using BFGS does not produce such an error and gives similar results:
> lme(conc ~ 1, data=IGF, random=~age|Lot, control = lmeControl(opt = 'optim'))
Linear mixed-effects model fit by REML
Data: IGF
Log-restricted-likelihood: -292.9675
Fixed: conc ~ 1
(Intercept)
5.333577
Random effects:
Formula: ~age | Lot
Structure: General positive-definite, Log-Cholesky parametrization
StdDev Corr
(Intercept) 0.032109976 (Intr)
age 0.005647296 -0.698
Residual 0.820819785
Number of Observations: 237
Number of Groups: 10
An alternative syntactical declaration of such a model can be done with the MUCH easier lme4
package:
library(lme4)
lmer(conc ~ 1 + (age | Lot), data=IGF)
which yields:
> lmer(conc ~ 1 + (age | Lot), data=IGF)
Linear mixed model fit by REML ['lmerMod']
Formula: conc ~ 1 + (age | Lot)
Data: IGF
REML criterion at convergence: 585.7987
Random effects:
Groups Name Std.Dev. Corr
Lot (Intercept) 0.056254
age 0.006687 -1.00
Residual 0.820609
Number of obs: 237, groups: Lot, 10
Fixed Effects:
(Intercept)
5.331
An attribute of lmer
and its optimizer is that random effects correlations which are very close to 1, 0, or -1 are simply set to those values since it simplifies the optimization (and statistical efficiency of the estimation) substantially.
Taken together, this does not suggest that age does not have an effect, as was said earlier, and this argument can be supported by the numeric results.