## test tidy, augment, glance methods from nlme-tidiers.R stopifnot(require("testthat"), require("broom.mixed"), require("nlme")) load(system.file("extdata", "nlme_example.rda", package = "broom.mixed", mustWork=TRUE)) if (suppressPackageStartupMessages(require(nlme, quietly = TRUE))) { context("nlme models") d <- as.data.frame(ChickWeight) colnames(d) <- c("y", "x", "subj", "tx") fit <- lme(y ~ tx * x, random = ~x | subj, data = d) test_that("tidy works on nlme/lme fits", { td <- tidy(fit) expect_equal( names(td), c( "effect", "group", "term", "estimate", "std.error", "df", "statistic", "p.value" ) ) td_ci <- tidy(fit, conf.int = TRUE) expect_equal( names(td_ci), c( "effect", "group", "term", "estimate", "std.error", "df", "statistic", "p.value", "conf.low", "conf.high" ) ) expect_equal(nrow(td_ci), 12) td_ci_95 <- tidy(fit, conf.int = TRUE, conf.level = 0.95) td_ci_25 <- tidy(fit, conf.int = TRUE, conf.level = 0.25) cols_ci <- c("conf.low", "conf.high") cols_other <- names(td_ci_95)[!names(td_ci_95) %in% cols_ci] expect_identical(td_ci_95[, cols_other], td_ci_25[, cols_other]) # FIXME: remove [1:11] subsetting in the two lines below once conf.int for # ran_pars Residual is implemented (see "FIXME: also do confint on # residual" in source file R/nlme_tidiers.R). expect_true(all(td_ci_95[["conf.low"]][1:11] < td_ci_25[["conf.low"]][1:11])) expect_true(all(td_ci_95[["conf.high"]][1:11] > td_ci_25[["conf.high"]][1:11])) }) test_that("tidy works on non-linear fits", { fm1 <- nlme(height ~ SSasymp(age, Asym, R0, lrc), data = Loblolly, fixed = Asym + R0 + lrc ~ 1, random = Asym ~ 1, start = c(Asym = 103, R0 = -8.5, lrc = -3.3) ) td <- expect_warning(tidy(fm1), "ran_pars not yet implemented") expect_equal( names(td), c( "effect", "term", "estimate", "std.error", "df", "statistic", "p.value" ) ) td_ran <- expect_warning(tidy(fm1, "ran_pars")) expect_is(td_ran, "tbl_df") expect_equal(ncol(td_ran), 1) expect_equal(nrow(td_ran), 0) td_fix <- tidy(fm1, "fixed") expect_equal( names(td_fix), c( "effect", "term", "estimate", "std.error", "df", "statistic", "p.value" ) ) td_ci <- tidy(fm1, "fixed", conf.int = TRUE) expect_equal( names(td_ci), c( "effect", "term", "estimate", "std.error", "df", "statistic", "p.value", "conf.low", "conf.high" ) ) td_ci_95 <- tidy(fm1, "fixed", conf.int = TRUE, conf.level = 0.95) td_ci_25 <- tidy(fm1, "fixed", conf.int = TRUE, conf.level = 0.25) cols_ci <- c("conf.low", "conf.high") cols_other <- names(td_ci_95)[!names(td_ci_95) %in% cols_ci] expect_identical(td_ci_95[, cols_other], td_ci_25[, cols_other]) expect_true(all(td_ci_95[["conf.low"]] < td_ci_25[["conf.low"]])) expect_true(all(td_ci_95[["conf.high"]] > td_ci_25[["conf.high"]])) }) test_that("augment works on lme fits with or without data", { au1 <- augment(fit) au2 <- augment(fit, d) expect_equal(au1, au2) expect_equal(dim(au1), c(578, 7)) }) dNAs <- d dNAs$y[c(1, 3, 5)] <- NA test_that("augment works on lme fits with NAs and na.omit", { fitNAs <- lme(y ~ tx * x, random = ~x | subj, data = dNAs, na.action = "na.omit" ) au <- augment(fitNAs) expect_equal(nrow(au), sum(complete.cases(dNAs))) }) test_that("augment works on lme fits with na.omit", { fitNAs <- lme(y ~ tx * x, random = ~x | subj, data = dNAs, na.action = "na.exclude" ) au <- augment(fitNAs, dNAs) # with na.exclude, should have NAs in the output where there were NAs in input expect_equal(nrow(au), nrow(dNAs)) expect_equal(complete.cases(au), complete.cases(dNAs)) }) test_that("glance includes deviance iff method='ML'", { expect(!("deviance" %in% names(glance(lmm0))),"deviance should not be in glance()") expect("deviance" %in% names(glance(lmm0ML)),"deviance should be in glance()") }) ## FIXME: weak tests - only shows that no error occurs and ## the right type is returned! test_that("glance works on nlme fits", { expect_is(glance(fit), "data.frame") }) testFit <- function(fit, data = NULL) { test_that("Pinheiro/Bates fit works", { expect_is(tidy(fit, "fixed"), "data.frame") # TODO: Better idea than suppressWarnings to avoid "ran_pars" ?? expect_is(suppressWarnings(tidy(fit)), "data.frame") expect_is(glance(fit), "data.frame") if (is.null(data)) { expect_is(augment(fit), "data.frame") } else { expect_is(augment(fit, data), "data.frame") } }) } testFit(lme(score ~ Machine, data = Machines, random = ~1 | Worker)) testFit(lme(score ~ Machine, data = Machines, random = ~1 | Worker, method = "ML")) testFit(lme(score ~ Machine, data = Machines, random = ~1 | Worker / Machine)) testFit(lme(pixel ~ day + day^2, data = Pixel, random = list(Dog = ~day, Side = ~1))) testFit(lme(pixel ~ day + day^2 + Side, data = Pixel, random = list(Dog = ~day, Side = ~1) )) testFit(lme(yield ~ ordered(nitro) * Variety, data = Oats, random = ~1 / Block / Variety )) # There are cases where no data set is returned in the result # We can do nothing about this inconsistency but give a useful error message in augment fit <- nlme(conc ~ SSfol(Dose, Time, lKe, lKa, lCl), data = Theoph, random = pdDiag(lKe + lKa + lCl ~ 1) ) test_that( "Fit without data in returned structure works when data are given", { expect_true(testFit(fit, Theoph)) } ) # When no data are passed, a meaningful message is issued expect_error(augment(fit), "explicit") context("gls models") test_that("basic gls tidying", { check_tidy(tidy(gls1), 3, 5, c("term","estimate","std.error","statistic","p.value")) check_tidy(tidy(gls1, conf.int=TRUE), 3, 7, c("term","estimate","std.error","statistic","p.value", "conf.low","conf.high")) }) test_that("basic gls augment with & without data", { au <- augment(gls1) expect_is(au, 'data.frame') expect_equal(nrow(au), nrow(Ovary)) expect_true(all(c(".fitted", ".resid") %in% names(au))) au <- augment(gls1, data = Ovary) expect_is(au, 'data.frame') expect_equal(nrow(au), nrow(Ovary)) expect_true(all(c(".fitted", ".resid") %in% names(au))) }) # Verify that the varFunc tidiers work #### ChickWeight_arbitrary_group <- ChickWeight %>% mutate( group_arb_n=1 + (as.integer(Chick) > median(as.integer(Chick))), group_arb=c("low", "high")[group_arb_n] ) fit <- lme(weight ~ Diet * Time, random = ~Time | Chick, data = ChickWeight) fit_varident <- lme(weight ~ Diet * Time, random = ~Time | Chick, data = ChickWeight_arbitrary_group, weights=varIdent(form=~1|group_arb)) fit_varcomb <- suppressWarnings(lme( weight ~ Diet * Time, random = ~Time | Chick, data = ChickWeight_arbitrary_group, weights= varComb( varIdent(form=~1|group_arb), varExp(form=~Time|group_arb) ), # This is just trying to make an object to test the model-- it's not # trying to actually make a good model. control=lmeControl(returnObject=TRUE) )) test_that("varFunc tidy works with no weights argument", { expect_true(sum(tidy(fit)$effect %in% "var_model") == 0) }) test_that("varFunc tidy works with a weights argument", { tidied_fit_varident <- tidy(fit_varident) expect_true(sum(tidied_fit_varident$effect %in% "var_model") == 2) expect_equal( tidied_fit_varident$group[tidied_fit_varident$effect %in% "var_model"], rep("varIdent(1 | group_arb)", 2) ) expect_equal( tidied_fit_varident$term[tidied_fit_varident$effect %in% "var_model"], c("low", "high") ) # The "estimated" column is not added unless it is needed expect_false("estimated" %in% names(tidied_fit_varident)) }) test_that("varComb tidy works", { tidied_fit_varcomb <- tidy(fit_varcomb) expect_true(sum(tidied_fit_varcomb$effect %in% "var_model") == 4) expect_equal( tidied_fit_varcomb$group[tidied_fit_varcomb$effect %in% "var_model"], rep(c("varIdent(1 | group_arb)", "varExp(Time | group_arb)"), each=2) ) expect_equal( tidied_fit_varcomb$term[tidied_fit_varcomb$effect %in% "var_model"], rep(c("low", "high"), 2) ) }) fit_varident_fixed <- lme( weight ~ Diet * Time, random = ~Time | Chick, data = ChickWeight_arbitrary_group, weights=varIdent(fixed=c("low"=5), form=~1|group_arb) ) # Two variables in fixed behave differently than one as the 'whichFix' # attribute is a vector and name matching must occur fit_varident_fixed_twovar <- lme( weight ~ Diet * Time, random = ~Time | Chick, data = ChickWeight_arbitrary_group, weights=varIdent(fixed=c("1*low"=5), form=~1|Diet*group_arb) ) test_that("varFunc with fixed shows the term correctly", { tidied_fit_varident_fixed <- tidy(fit_varident_fixed) expect_true(sum(tidied_fit_varident_fixed$effect %in% "var_model") == 2) expect_equal( tidied_fit_varident_fixed$group[tidied_fit_varident_fixed$effect %in% "var_model"], rep("varIdent(1 | group_arb)", 2) ) expect_equal( sum(tidied_fit_varident_fixed$estimated), nrow(tidied_fit_varident_fixed) - 1 ) }) test_that("varFunc with fixed and more complex grouping shows the term correctly", { tidied_fit_varident_fixed_twovar <- tidy(fit_varident_fixed_twovar) expect_true(sum(tidied_fit_varident_fixed_twovar$effect %in% "var_model") == 5) expect_equal( tidied_fit_varident_fixed_twovar$group[tidied_fit_varident_fixed_twovar$effect %in% "var_model"], rep("varIdent(1 | Diet * group_arb)", 5) ) expect_equal( sum(tidied_fit_varident_fixed_twovar$estimated), nrow(tidied_fit_varident_fixed_twovar) - 1 ) }) # Verify that fixed sigma works #### m1 <- lme(distance ~ age, random = ~age |Subject, data = Orthodont) m2 <- update(m1, control = lmeControl(sigma = 1)) tidy_no_fixed_sigma <- tidy(m1) tidy_yes_fixed_sigma <- tidy(m2) test_that("fixed sigma adds an 'estimated' column correctly", { expect_false("estimated" %in% names(tidy_no_fixed_sigma)) expect_true("estimated" %in% names(tidy_yes_fixed_sigma)) }) test_that("fixed sigma shows as fixed", { expect_false( tidy_yes_fixed_sigma$estimated[tidy_yes_fixed_sigma$group %in% "Residual"] ) expect_equal( sum(tidy_yes_fixed_sigma$estimated), nrow(tidy_yes_fixed_sigma) - 1 ) }) }