Rev 7854 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
### Methods for the class of random-effects structures.###### Copyright 2006-2020 The R Core team### Copyright 1997-2003 Jose C. Pinheiro,### Douglas M. Bates <bates@stat.wisc.edu>## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.## A copy of the GNU General Public License is available at# http://www.r-project.org/Licenses/###*## Generics that should be implemented for any reStruct class###*# ConstructorreStruct <-function(object, pdClass = "pdLogChol", REML = FALSE, data = sys.frame(sys.parent())){## object can be:## 1) a named list of formulas or pdMats with grouping factors as names## (assume same order of nesting as order of names)## 2) a formula of the form ~ x | g or ~ x | g1/g2/../gn## 3) a list of formulas like ~x | g## 4) a formula like ~x, a pdMat object, or a list of such## formulas or objects . In this case, the data used to## initialize the reStruct will be required to inherit from class## "groupedData"## 5) another reStruct object## parametrization specifies the pdMat constructor to be used for all## formulas used in objectif (inherits(object, "reStruct")) { # little to do, return objectif (!missing(REML)) attr(object, "settings")[1] <- as.integer(REML)object[] <- lapply(object, pdMat, data=data)return(object)}plen <- NULLif (inherits(object, "formula")) { # given as a formulaif (is.null(grpForm <- getGroupsFormula(object, asList = TRUE))) {object <- list( object )} else {if (length(object) == 3) { # nlme type of formulaobject <-eval(parse(text = paste(deparse(getResponseFormula(object)[[2]]),deparse(getCovariateFormula(object)[[2]], width.cutoff=500),sep = "~")))} else {object <- getCovariateFormula(object)}object <- rep( list(object), length( grpForm ) )names( object ) <- names( grpForm )}} else if (inherits(object, "pdMat")) { # single group, as pdMatif (is.null(formula(object))) {stop("\"pdMat\" element must have a formula")}object <- list(object)} else {if(!is.list(object))stop("'object' must be a list or a formula")## checking if nlme-type list - unnamed list of 2-sided formulasif (is.null(names(object)) &&all(vapply(object,function(el) inherits(el, "formula") && length(el) == 3,NA))) {object <- list(object)} else {## checking if elements are validobject <- lapply(object,function(el) {if (inherits(el, "pdMat")) {if (is.null(formula(el))) {stop("\"pdMat\" elements must have a formula")}return(el)}if (inherits(el, "formula")) {grpForm <- getGroupsFormula(el)if (!is.null(grpForm)) {el <- getCovariateFormula(el)attr(el, "grpName") <- deparse(grpForm[[2]])}return(el)} else {if (is.list(el) &&all(vapply(el, function(el1) {inherits(el1, "formula") && length(el1) == 3}, NA))) { return(el) }else {stop("elements in 'object' must be formulas or \"pdMat\" objects")}}})}if (is.null(namObj <- names(object))) {namObj <- rep("", length(object))}aux <- unlist(lapply(object,function(el) {if (inherits(el, "formula") &&!is.null(attr(el, "grpName"))) {attr(el, "grpName")} else ""}))auxNam <- namObj == ""if (any(auxNam)) {namObj[auxNam] <- aux[auxNam]}names(object) <- namObj}## converting elements in object to pdMat objectsobject <- lapply(object,function(el, pdClass, data) {# if (data.class(el) == "pdSymm")# warning("class pdSymm may cause problems if using analytic gradients")pdMat(el, pdClass = pdClass, data = data)}, pdClass = pdClass, data = data)object <- rev(object) # inner to outer groupsif (all(vapply(object, isInitialized, NA))) {plen <- unlist(lapply(object, function(el) length(coef(el))))}pC <- unlist(lapply(object, data.class)) ## FIXME! Wrong by designpC <- match(pC, c("pdSymm", "pdDiag", "pdIdent", "pdCompSymm","pdLogChol"), 0L) - 1L# if (any(pC == -1)) { # multiple nesting# pC <- -1# }## at this point, always require asDelta = TRUE and gradHess = 0attr(object, "settings") <- c(as.integer(REML), 1L, 0L, pC)attr(object, "plen") <- plenclass(object) <- "reStruct"object}###*# Methods for pdMat genericscorMatrix.reStruct <-function(object, ...){if (!isInitialized(object)) {stop("cannot access the matrix of uninitialized objects")}as.list(rev(lapply(object, corMatrix)))}pdFactor.reStruct <-function(object){unlist(lapply(object, pdFactor))}pdMatrix.reStruct <-function(object, factor = FALSE){if (!isInitialized(object)) {stop("cannot access the matrix of uninitialized objects")}as.list(rev(lapply(object, pdMatrix, factor)))}###*# Methods for standard genericsas.matrix.reStruct <-function(x, ...) pdMatrix(x)coef.reStruct <-function(object, unconstrained = TRUE, ...){unlist(lapply(object, coef, unconstrained))}"coef<-.reStruct" <-function(object, ..., value){if (is.null(plen <- attr(object, "plen"))) {stop("cannot change the parameter when length of parameters is undefined")}if (length(value) != sum(plen)) {stop("cannot change parameter length of initialized objects")}ends <- cumsum(plen)starts <- 1 + c(0, ends[-length(ends)])for (i in seq_along(object)) {coef(object[[i]]) <- value[(starts[i]):(ends[i])]}object}formula.reStruct <-function(x, asList = FALSE, ...){as.list(lapply(x, formula, asList))}getGroupsFormula.reStruct <-function(object, asList = FALSE, sep){if (is.null(val <- rev(formula(object)))) {stop("cannot extract groups formula without a formula")}if (is.null(nVal <- names(val))) return(NULL)if (asList) {for(i in nVal) {val[[i]] <- eval(parse(text = paste("~",i)))}} else {val <- eval(parse(text = paste("~",paste(nVal, collapse = "/"))))}val}isInitialized.reStruct <-function(object) all(unlist(lapply(object, isInitialized)))Initialize.reStruct <-function(object, data, conLin, control = list(niterEM = 20), ...){## initialize reStruct object, possibly getting initial estimatesseqO <- seq_along(object)## check if names are definedlNams <- unlist(lapply(object, function(el) length(Names(el)))) == 0if (any(lNams)) { # need to resolve formula namesaux <- seqO[lNams]object[aux] <- lapply(object[aux],function(el, data) {pdConstruct(el, el, data = data)}, data = data)}## obtaining the parameters mappingplen <- unlist(lapply(object, function(el){if (isInitialized(el)) {length(coef(el))} else {matrix(el) <- diag(length(Names(el)))length(coef(el))}}))if (!all(plen > 0)) {stop("all elements of a \"reStruct\" object must have a non-zero size")}attr(object, "plen") <- plen## checking initializationisIni <- vapply(object, isInitialized, NA)if (!all(isIni)) { # needs initializationdims <- conLin$dimsQ <- dims$Qqvec <- dims$qvec[1:Q]auxInit <-lapply(split(0.375^2 * colSums((conLin$Xy[, 1:sum(qvec), drop = FALSE])^2) /rep(dims$ngrps[1:Q], qvec), rep(1:Q, qvec)),function(x) diag(x, length(x)))}for(i in seqO) {if (isIni[i]) {object[[i]] <- solve(object[[i]]) #working with precisions} else {matrix(object[[i]]) <- auxInit[[i]]}NULL}MEEM(object, conLin, control$niterEM) # refine initial estimates with EM}logDet.reStruct <- function(object, ...) vapply(object, logDet, numeric(1))logLik.reStruct <- function(object, conLin, ...){if(any(!is.finite(conLin$Xy))) return(-Inf)## 17-11-2015; Fixed sigma patch; SH Heisterkamp; Quantitative Solutionsdims <- conLin$dimssettings <- as.integer(attr(object, "settings"))REML <- settings[[1L]]val <- .C(mixed_loglik,as.double(conLin$Xy),as.integer(unlist(conLin$dims)),as.double(pdFactor(object)),settings, ## == c(REML, asDelta {= 1L}, gradHess {= 0L}, pdClass {= pC})loglik = double(1),lRSS = double(1),as.double(conLin$sigma))if (conLin$sigma > 0 && REML == 1) {## nc <- dims$ncol; p <- nc[dims$Q + 1]N <- dims$Naux <- N * log(conLin$sigma) - exp(val[["lRSS"]]) / (2*conLin$sigma)val[["loglik"]] + aux} else {val[["loglik"]]}}"matrix<-.reStruct" <-function(object, value){if (data.class(value) != "list") value <- list(value)if (length(value) != length(object)) {stop("cannot change the length of 'object'")}value <- rev(value) # same order as objectfor(i in seq_along(object)) {matrix(object[[i]]) <- value[[i]]}object}model.matrix.reStruct <-function(object, data, contrast = NULL, ...){if (is.null(form <- formula(object, asList = TRUE))) {stop("cannot extract model matrix without formula")}form1 <- asOneFormula(form)if (length(form1) > 0) {data <- model.frame(form1, data = data)} else {data <- data.frame("(Intercept)" = rep(1, nrow(data)))}any2list <- function( object, data, contrast ) {form2list <- function(form, data, contrast) {if (length(asOneFormula( form )) == 0) {# the ~ 1 casereturn(list("(Intercept)" = rep(1, dim(data)[1])))}as.data.frame(unclass(model.matrix(form,model.frame(form, data),contrast)))}if (inherits( object, "formula" )) {return( form2list( object, data, contrast ) )}if (is.list( object ) ) {return( unlist(lapply(object, form2list, data = data, contrast = contrast),recursive = FALSE ) )}return( NULL)}value <- as.list(lapply(form, any2list,data = data, contrast = contrast))## save the contrasts currently in effect for later predictionscontr <- as.list(lapply( as.data.frame(data), function(x)if( inherits( x, "factor" ) &&length(levels(x)) > 1) contrasts(x) else NULL ))contr[names(contrast)] <- contrastncols <- lengths(value)nams <- if (length(value) == 1) {names(value[[1]])} else {paste(rep(names(value), ncols), unlist(lapply(value, names)), sep = ".")}structure(matrix(unlist(value), nrow = nrow(data),dimnames = list(row.names(data), nams)),ncols = ncols,nams = lapply(value, names),contr = contr)}Names.reStruct <-function(object, ...){as.list(lapply(object, Names))}"Names<-.reStruct" <-function(object, ..., value){if (length(object) != length(value)) {stop("incompatible lengths for object names")}for(i in seq_along(object)) {Names(object[[i]]) <- value[[i]]}object}needUpdate.reStruct <-function(object) FALSEprint.reStruct <-function(x, sigma = 1, reEstimates, verbose = FALSE, ...){ox <- xif (isInitialized(x)) {nobj <- length(x)if (is.null(names(x))) names(x) <- nobj:1aux <- t(array(rep(names(x), nobj), c(nobj, nobj)))aux[lower.tri(aux)] <- ""x[] <- rev(x)names(x) <-rev(apply(aux, 1, function(x) paste(x[x != ""], collapse = " %in% ")))cat("Random effects:\n")for(i in seq_along(x)) {print(summary(x[[i]]), sigma, Level = names(x)[i],resid = (i == length(x)), ...)if (verbose) {cat("Random effects estimates:\n")print(reEstimates[[i]])}cat("\n")}} else {cat("Uninitialized random effects structure\n")}invisible(ox)}recalc.reStruct <-function(object, conLin, ...){conLin[["logLik"]] <- conLin[["logLik"]] + logLik(object, conLin)conLin}solve.reStruct <-function(a, b, ...){a[] <- lapply(a, solve)a}summary.reStruct <- function(object, ...) objectupdate.reStruct <- function(object, data, ...) object"[.reStruct" <- function(x, ...){val <- NextMethod()if (length(val)) class(val) <- "reStruct"val}