### test-auto-residuals.R ---
##----------------------------------------------------------------------
## Author: Brice Ozenne
## Created: nov 4 2021 (11:49)
## Version:
## Last-Updated: maj 7 2024 (13:58)
## By: Brice Ozenne
## Update #: 37
##----------------------------------------------------------------------
##
### Commentary:
##
### Change Log:
##----------------------------------------------------------------------
##
### Code:
if(FALSE){
library(testthat)
library(ggplot2)
library(LMMstar)
}
context("Check residuals and partial residuals calculation")
LMMstar.options(optimizer = "FS", method.numDeriv = "simple", precompute.moments = TRUE,
columns.confint = c("estimate","se","df","lower","upper","p.value"))
## * Linear model
set.seed(10)
dL <- sampleRem(100, n.times = 3, format = "long")
test_that("linear model",{
e.lm <- lm(Y~visit+X1+X2+X6, data = dL)
GS <- residuals(e.lm, type = "partial")
## single variable
e.lmm <- lmm(Y~visit+X1+X2+X6, data = dL)
test1 <- residuals(e.lmm, type = "partial-center", variable = "X1")
expect_equal(as.double(test1), as.double(GS[,"X1"]), tol = 1e-6)
## same but with another reference
test2 <- residuals(e.lmm, type = "partial", variable = "X1")
e.diff <- mean(e.lmm$design$mean[,"X1"] * coef(e.lmm)["X1"]) ## expected difference
expect_equal(as.double(test2-test1), rep(e.diff,length(test1)), tol = 1e-6)
## note: only match with continuous covariate
test1.bis <- residuals(e.lmm, type = "partial-center", variable = "visit")
e.diff.bis <- mean(e.lmm$design$mean[,c("visit2","visit3"),drop=FALSE] %*% coef(e.lmm)[c("visit2","visit3")]) ## expected difference
expect_equal(as.double(test1.bis - GS[,"visit"]), rep(e.diff.bis,length(test1)), tol = 1e-6)
## plot(e.lmm, type = "partial", variable = "X1")
## plot(e.lmm, type = "partial", variable = c("(Intercept)","X1"))
})
## ** Linear model with interaction
test_that("linear model with interaction",{
e.lmm <- lmm(Y~visit*X6+X2+X5, data = dL)
## plot(e.lmm, type = "partial", variable = c("visit","X6"))
## plot(e.lmm, type = "partial", variable = c("visit","X6","(Intercept)"))
test1 <- residuals(e.lmm, type = "partial", variable = c("visit","X6"))
GS1 <- dL$Y - coef(e.lmm)["(Intercept)"] - coef(e.lmm)["X2"]*dL$X2 - coef(e.lmm)["X5"]*dL$X5
expect_equal(as.double(test1), as.double(GS1), tol = 1e-6)
test2 <- residuals(e.lmm, type = "partial", variable = c("visit","X6","(Intercept)"))
GS2 <- dL$Y - coef(e.lmm)["X2"]*dL$X2 - coef(e.lmm)["X5"]*dL$X5
expect_equal(as.double(test2), as.double(GS2), tol = 1e-6)
})
## ** Linear model with splines
test_that("linear model with splines",{
## 1- poly
ePOLY.lm <- lm(Y~visit+X1+stats::poly(X6,4), data = dL)
ePOLY.lmm <- lmm(Y~visit+X1+stats::poly(X6, 4), data = dL)
## plot(ePOLY.lmm, type = "partial", variable = "X6")
## compare predictions
GS.POLY <- predict(ePOLY.lm, newdata = dL[1:2,])
test.POLY <- predict(ePOLY.lmm, newdata = dL[1:2,])
expect_equal(as.double(test.POLY), as.double(GS.POLY), tol = 1e-6)
## compare partial residuals
test.POLY <- residuals(ePOLY.lmm, type = "partial", variable = "X6")
GS.POLY <- dL$Y - coef(ePOLY.lm)["(Intercept)"] - dL$X1 * coef(ePOLY.lm)["X1"] - c(0,coef(ePOLY.lm)[c("visit2","visit3")])[as.numeric(dL$visit)]
expect_equal(as.double(GS.POLY), as.double(test.POLY), tol = 1e-6)
## ## 2- ns
eNS.lm <- lm(Y~visit+X1+splines::ns(X6,4), data = dL)
eNS.lmm <- lmm(Y~visit+X1+splines::ns(X6, 4), data = dL)
## plot(eNS.lmm, type = "partial", variable = "X6")
## ## compare predictions
GS.NS <- predict(eNS.lm, newdata = dL[1:2,])
test.NS <- predict(eNS.lmm, newdata = dL[1:2,])
expect_equal(as.double(test.NS), as.double(GS.NS), tol = 1e-6)
## ## compare partial residuals
test.NS <- residuals(eNS.lmm, type = "partial", variable = "X6")
GS.NS <- dL$Y - coef(eNS.lm)["(Intercept)"] - dL$X1 * coef(eNS.lm)["X1"] - c(0,coef(eNS.lm)[c("visit2","visit3")])[as.numeric(dL$visit)]
expect_equal(as.double(GS.NS), as.double(test.NS), tol = 1e-6)
})
## * Linear mixed model
test_that("linear mixed model",{
## without missing values
e.lmm <- lmm(Y~visit+X1+X2+X5, repetition = ~visit|id, data = dL)
pRes <- residuals(e.lmm, type = "partial", variable = c("(Intercept)","visit","X1"), keep.data = TRUE)
GS <- coef(e.lmm)
test <- coef(lmm(r.partial ~ visit + X1, repetition = ~visit|id, data = pRes))
expect_equal(GS[names(test)],test, tol = 1e-4)
## only match lm when full interaction with time due to unstructure covariance matrix
expect_equal(coef(lm(r.partial ~ visit + X1, data = pRes))[c("visit2","visit3")],
test[c("visit2","visit3")], tol = 1e-3)
## with missing values (only approximate equality)
dLNA <- dL
dLNA$Y[c(79, 13, 191, 139, 75, 213, 78, 4, 246, 274)] <- NA
e.lmmNA <- lmm(Y~visit:X1+X2+X5, repetition = ~visit|id, data = dLNA)
pResNA <- residuals(e.lmmNA, type = "partial", variable = c("(Intercept)","visit","X1"), keep.data = TRUE)
GS <- coef(e.lmmNA)
test <- coef(lmm(r.partial ~ visit:X1, repetition = ~visit|id, data = pResNA))
expect_equal(GS[names(test)],test, tol = 1e-2)
## pResNA2 <- fitted(e.lmmNA, type = "outcome", keep.data = TRUE)
## pResNA2$r.partial <- pResNA2$Y - coef(e.lmmNA)["X2"]*pResNA2$X2 - coef(e.lmmNA)["X5"]*pResNA2$X5
## test2 <- coef(lmm(r.partial ~ visit:X1, repetition = ~visit|id, data = pResNA2))
## expect_equal(GS[names(test2)],test2, tol = 1e-3)
})
## * Linear mixed model (gradient)
data(gastricbypassL, package = "LMMstar")
e.lmm <- lmm(glucagonAUC ~ weight + visit + (1|id), data = gastricbypassL)
test_that("gradient of the residuals in lmm",{
test <- residuals(e.lmm, type = c("response","pearson","studentized","normalized","normastudentized"), simplify = FALSE, keep.data = TRUE, fitted.ci = TRUE)
GS <- estimate(e.lmm, transform.sigma = "log", transform.rho = "atanh", function(p){ ## p <- NULL
iRes <- residuals(e.lmm, type = c("response","pearson","studentized","normalized","normastudentized"), p = p, keep.data = TRUE)
c(iRes$fitted,iRes$r.response,iRes$r.pearson,iRes$r.studentized,iRes$r.normalized,iRes$r.normastudentized)
}, method.numDeriv = "Richardson")
expect_equivalent(attr(GS,"grad")[1:80,], attr(test,"grad")[,,"fitted"], tol = 1e-6)
expect_equivalent(attr(GS,"grad")[81:160,], attr(test,"grad")[,,"r.response"], tol = 1e-6)
expect_equivalent(attr(GS,"grad")[161:240,], attr(test,"grad")[,,"r.pearson"], tol = 1e-6)
expect_equivalent(attr(GS,"grad")[241:320,], attr(test,"grad")[,,"r.studentized"], tol = 1e-6)
expect_equivalent(attr(GS,"grad")[321:400,], attr(test,"grad")[,,"r.normalized"], tol = 1e-6)
expect_equivalent(attr(GS,"grad")[401:480,], attr(test,"grad")[,,"r.normastudentized"], tol = 1e-6)
test.se <- sqrt(diag(attr(test,"grad")[,,"r.normalized"] %*% vcov(e.lmm, effects = "all") %*% t(attr(test,"grad")[,,"r.normalized"])))
expect_equivalent(GS$se[321:400], test.se, tol = 1e-6)
test2 <- residuals(e.lmm, variable = "weight", type = "partial", simplify = FALSE, keep.data = TRUE, fitted.ci = TRUE)
grad.NA <- attr(test2,"grad")[is.na(gastricbypassL$glucagonAUC),,"r.partial"]
grad.NNA <- attr(test2,"grad")[!is.na(gastricbypassL$glucagonAUC),,"r.partial"]
expect_true(all(is.na(grad.NA)))
expect_true(all(grad.NNA[,"(Intercept)"]==-1))
expect_true(all(grad.NNA[,"visit2"]==-(gastricbypassL$visit[!is.na(gastricbypassL$glucagonAUC)]=="2")))
expect_true(all(grad.NNA[,"visit3"]==-(gastricbypassL$visit[!is.na(gastricbypassL$glucagonAUC)]=="3")))
expect_true(all(grad.NNA[,"visit4"]==-(gastricbypassL$visit[!is.na(gastricbypassL$glucagonAUC)]=="4")))
expect_true(all(grad.NNA[,c("weight","sigma","rho(id)")]==0))
})
##----------------------------------------------------------------------
### test-auto-residuals.R ends here
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.