Nothing
#' Convenience wrappers for car::Anova using either a formula or factor based interface.
#'
#' These functions allow convenient access to \code{\link[car]{Anova}} (from the \pkg{car} package) for data in the \strong{long} format (i.e., one observation per row), possibly aggregating the data if there is more than one obersvation per individuum and cell. Hence, mixed between-within ANOVAs can be calculated conveniently without using the rather unhandy format of \code{car::Anova}. \code{aov.car} can be called using a formula similar to \code{\link{aov}} specifying an error strata for the within-subject factor(s). \code{ez.glm} is called specifying the factors as character vectors.
#'
#' @usage aov.car(formula, data, fun.aggregate = NULL, type = 3, ...)
#'
#' ez.glm(id, dv, data, between = NULL, within = NULL, covariate = NULL, fun.aggregate = NULL, type = 3, ..., print.formula = FALSE)
#'
#' univariate(object)
#'
#' @param formula A formula specifying the ANOVA model similar to \code{\link{aov}}. Should include an error term (i.e., \code{Error( / )}). Note that the within-subject factors do not need to be outside the Error term (this contrasts with \code{aov}). See Details.
#' @param id \code{character} vector (of length 1) indicating the subject identifier column in \code{data}.
#' @param dv \code{character} vector (of length 1) indicating the column containing the \strong{dependent variable} in \code{data}.
#' @param between \code{character} vector indicating the \strong{between}-subject(s) factor(s)/column(s) in \code{data}. Default is \code{NULL} indicating no between-subjects factors.
#' @param within \code{character} vector indicating the \strong{within}-subject(s) factor(s)/column(s) in \code{data}. Default is \code{NULL} indicating no within-subjects factors.
#' @param covariate \code{character} vector indicating the between-subject(s) covariate(s) (i.e., column(s)) in \code{data}. Default is \code{NULL} indicating no covariates.
#' @param data A \code{data.frame} containing the data. Mandatory.
#' @param fun.aggregate The function for aggregating the data before running the ANOVA if there is more than one obervation per individuum and cell of the design. The default \code{NULL} issues a warning if aggregation is necessary and uses \code{\link{mean}}.
#' @param type The type of sums of squares for the ANOVA. \strong{Defaults to 3}. Passed to \code{\link[car]{Anova}}. Possible values are \code{"II"}, \code{"III"}, \code{2}, or \code{3}.
#' @param print.formula \code{ez.glm} is a wrapper for \code{aov.car}. This boolean argument indicates whether the formula in the call to \code{car.aov} should be printed.
#' @param ... Further arguments passed to \code{fun.aggregate}.
#' @param object An object of class \code{Anova.mlm} as returned by \code{aov.car}, \code{ez.glm}, or \code{\link[car]{Anova}}.
#'
#' @return \code{aov.car} and \code{ez.glm} are wrappers and therfore return the same as \code{\link[car]{Anova}}. Usually an object of class \code{"Anova.mlm"} (with within-subjects factors) or \code{c("anova", "data.frame")}.
#'
#' \code{univariate} returns a \code{list} of \code{data.frame}s containing the univariate results (i.e., the classical ANOVA results) from an object of class \code{"Anova.mlm"}. This is essentially the output from \code{summary.Anova.mlm} with \code{multivariate = FALSE}, e.g. \code{summary(aov.car(...), multivriate = FALSE)}, as a list instead of printed to the console.\cr
#' For objects of class \code{"anova"} (i.e., the object returned by \code{car::Anova} for a purely between-subjects ANOVA) the object is returned unaltered.
#'
#' The elements of the list returned by \code{univariate} are: \code{anova}, \code{mauchly}, and \code{spehricity.correction} (containing both, Greenhouse-Geisser and Hyundt-Feldt correction).
#'
#' @details \strong{Type 3 sums of squares are default in \pkg{afe}.} Note that type 3 sums of squares are said to be dangerous and/or problematic. On the other side they are the default in in SPSS and SAS and recommended by e.g. Maxwell and Delaney (2003). For a brief discussion see \href{http://stats.stackexchange.com/q/6208/442}{here}.
#'
#' However, note that lower order effects (e.g., main effects) in type 3 ANOVAs are only meaningful with \href{http://www.ats.ucla.edu/stat/mult_pkg/faq/general/effect.htm}{effects coding}. That is, contrasts should be set to \code{\link{contr.sum}} via \code{options(contrasts=c('contr.sum','contr.poly'))}. This should be done automatically when loading \pkg{afe} and \pkg{afe} will issue a warning when running type 3 SS and \href{http://www.ats.ucla.edu/stat/r/library/contrast_coding.htm}{other coding schemes}. You can check the coding with \code{options("contrasts")}.
#'
#' The \code{formula} for \code{aov.car} must contain a single \code{Error} term specyfying the \code{ID} column and potential within-subject factors. Factors outside the \code{Error} term are treated as between-subject factors (the within-subject factors specified in the \code{Error} term are ignored outside the \code{Error} term, i.e., it is not necessary to specify them outside the \code{Error} term, see Examples). Suppressing the intercept (i.e, via \code{0 +} or \code{- 1}) is ignored. Specific specifications of effects (e.g., excluding terms with \code{-} or using \code{^}) should be functional. Using the \code{\link{I}} or \code{\link{poly}} function within the formula is not tested and not supported!
#'
#' For \code{ez.glm} either \code{between} or \code{within} must not be \code{NULL}.
#'
#' \code{ez.glm} will concatante all between-subject factors using \code{*} (i.e., producing all main effects and interactions) and all covariates by \code{+} (i.e., adding only the main effects to the existing between-subject factors). The within-subject factors do fully interact with all between-subject factors and covariates. This is essentially identical to the behavior of SPSS's \code{glm} function.
#'
#' @author \code{univariate} is basically a copy of \code{\link[car]{summary.Anova.mlm}} written by John Fox.\cr The other functions were written by Henrik Singmann.
#'
#' @note Variables entered as within-subjects (i.e., repeated measures) factors are silently converted to factors and unused levels dropped.
#'
#' Contrasts attached to a factor as an attribute are probably not preserved and not supported.
#'
#' @seealso \code{\link{nice.anova}} is a function for creating nice ANOVA tables (including sphercitiy corrections) from objects returned by \code{ez.glm} and \code{aov.car}.
#'
#' \code{\link{obk.long}} describes the long version of the \code{OBrienKaiser} dataset used in the examples.
#'
#' @name aov.car
#' @aliases aov.car ez.glm univariate
#' @export aov.car ez.glm univariate
#' @examples
#'
#' # exampel using obk.long (see ?obk.long), a long version of the OBrienKaiser dataset from car.
#' data(obk.long)
#'
#' # run univariate mixed ANCOVA for the full design:
#' univariate(aov.car(value ~ treatment * gender + age + Error(id/phase*hour), data = obk.long))
#' univariate(ez.glm("id", "value", obk.long, c("treatment", "gender"), c("phase", "hour"), "age"))
#'
#' # both calls return the same:
#'
#' ## $anova
#' ## SS num Df Error SS den Df F Pr(>F)
#' ## (Intercept) 6454.236987 1 215.65658 9 269.3547893 5.152317e-08
#' ## treatment 171.399953 2 215.65658 9 3.5765187 7.193619e-02
#' ## gender 94.598340 1 215.65658 9 3.9478742 7.818280e-02
#' ## age 12.398975 1 215.65658 9 0.5174466 4.901885e-01
#' ## treatment:gender 61.531858 2 215.65658 9 1.2839551 3.231798e-01
#' ## phase 134.586005 2 59.72439 18 20.2810632 2.448505e-05
#' ## treatment:phase 80.604542 4 59.72439 18 6.0732385 2.826803e-03
#' ## gender:phase 1.634246 2 59.72439 18 0.2462681 7.843036e-01
#' ## age:phase 20.553392 2 59.72439 18 3.0972362 6.982439e-02
#' ## treatment:gender:phase 21.254421 4 59.72439 18 1.6014379 2.170946e-01
#' ## hour 108.513510 4 47.59543 36 20.5192290 7.001584e-09
#' ## treatment:hour 7.547869 8 47.59543 36 0.7136275 6.779072e-01
#' ## gender:hour 3.746135 4 47.59543 36 0.7083708 5.915285e-01
#' ## age:hour 14.904567 4 47.59543 36 2.8183608 3.926421e-02
#' ## treatment:gender:hour 6.235198 8 47.59543 36 0.5895186 7.798264e-01
#' ## phase:hour 9.762579 8 88.62706 72 0.9913814 4.501348e-01
#' ## treatment:phase:hour 6.579092 16 88.62706 72 0.3340505 9.915014e-01
#' ## gender:phase:hour 8.851396 8 88.62706 72 0.8988515 5.222336e-01
#' ## age:phase:hour 7.539611 8 88.62706 72 0.7656409 6.339004e-01
#' ## treatment:gender:phase:hour 12.822199 16 88.62706 72 0.6510416 8.307936e-01
#' ##
#' ## $mauchly
#' ## Test statistic p-value
#' ## phase 0.8217571566 0.45600959
#' ## treatment:phase 0.8217571566 0.45600959
#' ## gender:phase 0.8217571566 0.45600959
#' ## age:phase 0.8217571566 0.45600959
#' ## treatment:gender:phase 0.8217571566 0.45600959
#' ## hour 0.0966749877 0.04923980
#' ## treatment:hour 0.0966749877 0.04923980
#' ## gender:hour 0.0966749877 0.04923980
#' ## age:hour 0.0966749877 0.04923980
#' ## treatment:gender:hour 0.0966749877 0.04923980
#' ## phase:hour 0.0002379741 0.08651564
#' ## treatment:phase:hour 0.0002379741 0.08651564
#' ## gender:phase:hour 0.0002379741 0.08651564
#' ## age:phase:hour 0.0002379741 0.08651564
#' ## treatment:gender:phase:hour 0.0002379741 0.08651564
#' ##
#' ## $sphericity.correction
#' ## GG eps Pr(>F[GG]) HF eps Pr(>F[HF])
#' ## phase 0.8487215 8.383485e-05 1.0252867 2.448505e-05
#' ## treatment:phase 0.8487215 5.159591e-03 1.0252867 2.826803e-03
#' ## gender:phase 0.8487215 7.493990e-01 1.0252867 7.843036e-01
#' ## age:phase 0.8487215 8.073373e-02 1.0252867 6.982439e-02
#' ## treatment:gender:phase 0.8487215 2.279698e-01 1.0252867 2.170946e-01
#' ## hour 0.5341747 1.302016e-05 0.7054545 8.046331e-07
#' ## treatment:hour 0.5341747 6.010781e-01 0.7054545 6.342676e-01
#' ## gender:hour 0.5341747 5.137213e-01 0.7054545 5.478398e-01
#' ## age:hour 0.5341747 8.155027e-02 0.7054545 6.211130e-02
#' ## treatment:gender:hour 0.5341747 6.843526e-01 0.7054545 7.263729e-01
#' ## phase:hour 0.4355822 4.186799e-01 0.7444364 4.402119e-01
#' ## treatment:phase:hour 0.4355822 9.317848e-01 0.7444364 9.787985e-01
#' ## gender:phase:hour 0.4355822 4.651930e-01 0.7444364 5.020890e-01
#' ## age:phase:hour 0.4355822 5.395151e-01 0.7444364 5.992844e-01
#' ## treatment:gender:phase:hour 0.4355822 7.100921e-01 0.7444364 7.878433e-01
#' ##
#' ## Warning message:
#' ## In univariate(aov.car(value ~ treatment * gender + age + Error(id/phase * :
#' ## HF eps > 1 treated as 1
#'
#' # To get a nicer ANOVA table use function nice.anova (see ?noce.anova):
#' nice.anova(ez.glm("id", "value", obk.long, c("treatment", "gender"), c("phase", "hour"), "age"))
#'
#' ## Effect df MSE F p
#' ## 1 treatment 2, 9 23.96 3.58 + .07
#' ## 2 gender 1, 9 23.96 3.95 + .08
#' ## 3 age 1, 9 23.96 0.52 .49
#' ## 4 treatment:gender 2, 9 23.96 1.28 .32
#' ## 5 phase 1.7, 15.28 3.91 20.28 *** <.001
#' ## 6 treatment:phase 3.39, 15.28 3.91 6.07 ** .005
#' ## 7 gender:phase 1.7, 15.28 3.91 0.25 .75
#' ## 8 age:phase 1.7, 15.28 3.91 3.10 + .08
#' ## 9 treatment:gender:phase 3.39, 15.28 3.91 1.60 .23
#' ## 10 hour 2.14, 19.23 2.48 20.52 *** <.001
#' ## 11 treatment:hour 4.27, 19.23 2.48 0.71 .60
#' ## 12 gender:hour 2.14, 19.23 2.48 0.71 .51
#' ## 13 age:hour 2.14, 19.23 2.48 2.82 + .08
#' ## 14 treatment:gender:hour 4.27, 19.23 2.48 0.59 .68
#' ## 15 phase:hour 3.48, 31.36 2.83 0.99 .42
#' ## 16 treatment:phase:hour 6.97, 31.36 2.83 0.33 .93
#' ## 17 gender:phase:hour 3.48, 31.36 2.83 0.90 .47
#' ## 18 age:phase:hour 3.48, 31.36 2.83 0.77 .54
#' ## 19 treatment:gender:phase:hour 6.97, 31.36 2.83 0.65 .71
#'
#' # replicating ?Anova using aov.car:
#' aov.car(value ~ treatment * gender + Error(id/phase*hour), data = obk.long, type = 2)
#' # in contrast to aov you do not need the within-subject factors outside Error()
#'
#' # replicating ?Anova using ez.glm:
#' ez.glm("id", "value", obk.long, c("treatment", "gender"), c("phase", "hour"), type = 2)
#'
#' #both return:
#' ## Type II Repeated Measures MANOVA Tests: Pillai test statistic
#' ## Df test stat approx F num Df den Df Pr(>F)
#' ## (Intercept) 1 0.970 318 1 10 0.0000000065 ***
#' ## treatment 2 0.481 5 2 10 0.03769 *
#' ## gender 1 0.204 3 1 10 0.14097
#' ## treatment:gender 2 0.364 3 2 10 0.10447
#' ## phase 1 0.851 26 2 9 0.00019 ***
#' ## treatment:phase 2 0.685 3 4 20 0.06674 .
#' ## gender:phase 1 0.043 0 2 9 0.82000
#' ## treatment:gender:phase 2 0.311 1 4 20 0.47215
#' ## hour 1 0.935 25 4 7 0.00030 ***
#' ## treatment:hour 2 0.301 0 8 16 0.92952
#' ## gender:hour 1 0.293 1 4 7 0.60237
#' ## treatment:gender:hour 2 0.570 1 8 16 0.61319
#' ## phase:hour 1 0.550 0 8 3 0.83245
#' ## treatment:phase:hour 2 0.664 0 16 8 0.99144
#' ## gender:phase:hour 1 0.695 1 8 3 0.62021
#' ## treatment:gender:phase:hour 2 0.793 0 16 8 0.97237
#' ## ---
#' ## Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#'
#'
#' # aggregating over one within-subjects factor (phase) with warning:
#'
#' aov.car(value ~ treatment * gender + age + Error(id/hour), data = obk.long)
#'
#' ez.glm("id", "value", obk.long, c("treatment", "gender"), "hour", "age")
#'
#'
#' # runs with "numeric" factors
#' obk.long$hour2 <- as.numeric(as.character(obk.long$hour))
#'
#' aov.car(value ~ treatment * gender + Error(id/hour2), data = obk.long, type = 2)
#'
#' # only between
#' aov.car(value ~ treatment * gender + age + Error(id), data = obk.long, type = 2)
#' aov.car(value ~ treatment * gender + Error(id), data = obk.long, type = 2)
#'
#' ez.glm("id", "value", obk.long, c("treatment", "gender"), within = NULL, covariate = "age", type = 2, print.formula = TRUE)
#'
#' ez.glm("id", "value", obk.long, c("treatment", "gender"), within = NULL, type = 2, print.formula = TRUE)
#'
#' # only within
#'
#' univariate(aov.car(value ~ Error(id/phase*hour), data = obk.long, type = 2))
#'
#' univariate(ez.glm("id", "value", obk.long, NULL, c("phase", "hour"), type = 2, print.formula = TRUE))
#'
#'
aov.car <- function(formula, data, fun.aggregate = NULL, type = 3, ...) {
#browser()
# stuff copied from aov:
Terms <- terms(formula, "Error", data = data)
indError <- attr(Terms, "specials")$Error
if (length(indError) > 1L)
stop(sprintf(ngettext(length(indError), "there are %d Error terms: only 1 is allowed",
"there are %d Error terms: only 1 is allowed"), length(indError)),
domain = NA)
# from here, code by Henrik Singmann:
vars <- all.vars(formula)
dv <- vars[1]
vars <- vars[-1]
parts <- attr(terms(formula, "Error", data = data), "term.labels")
error.term <- parts[str_detect(parts, "^Error\\(")]
id <- all.vars(parse(text = error.term))[1]
within <- all.vars(parse(text = error.term))[-1]
between <- vars[!(vars %in% c(id, within))]
effect.parts <- parts[!str_detect(parts, "^Error\\(")]
effect.parts.no.within <- effect.parts[!str_detect(effect.parts, str_c("\\<",within,"\\>", collapse = "|"))]
rh2 <- if (length(between) > 0) str_c(effect.parts.no.within, collapse = "+") else "1"
lh1 <- str_c(id, if (length(between) > 0) str_c(between, collapse = "+") else NULL, sep = "+")
rh1 <- str_c(within, collapse = "+")
rh3 <- str_c(within, collapse = "*")
# converting all within subject factors to factors and adding a leading charcter (x) if starting with a digit.
for (within.factor in within) {
data[,within.factor] <- factor(data[,within.factor])
levels(data[,within.factor])[grep("^[[:digit:]]", levels(data[,within.factor]))] <- str_c("x", levels(data[,within.factor])[grep("^[[:digit:]]", levels(data[,within.factor]))])
}
# Is fun.aggregate NULL and aggregation necessary?
if (is.null(fun.aggregate)) {
if (any(xtabs(as.formula(str_c("~", id, if (length(within) > 0) "+", rh1)), data = data) > 1)) {
warning("More than one observation per cell, aggregating the data using mean (i.e, fun.aggregate = mean)!")
fun.aggregate <- mean
}
}
# Is Type = 3 and contrasts not contr.sum?
if ((type == 3 | type == "III") & options("contrasts")[[1]][1] != "contr.sum") warning(str_c("Calculating Type 3 sums with contrasts = ", options("contrasts")[[1]][1], ".\n Use options(contrasts=c('contr.sum','contr.poly')) instead"))
# prepare the data:
tmp.dat <- dcast(data, formula = as.formula(str_c(lh1, if (length(within) > 0) rh1 else ".", sep = "~")), fun.aggregate = fun.aggregate, ..., value.var = dv)
# branching based on type of ANOVA
if (length(within) > 0) { # if within-subject factors are present:
# make idata argument
if (length(within) > 1) {
within.levels <- lapply(lapply(data[,within], levels), factor)
idata <- rev(expand.grid(rev(within.levels)))
} else {
idata <- data.frame(levels(data[,within]))
colnames(idata) <- within
}
# print(as.formula(str_c("cbind(",str_c(colnames(tmp.dat[-(seq_along(c(id, between)))]), collapse = ", "), ") ~ ", rh2)))
tmp.lm <- lm(as.formula(str_c("cbind(",str_c(colnames(tmp.dat[-(seq_along(c(id, between)))]), collapse = ", "), ") ~ ", rh2)), data = tmp.dat)
Anova(tmp.lm, idata = idata, idesign = as.formula(str_c("~", rh3)), type = type)
} else { # if NO within-subjetc factors are present (i.e., purley between ANOVA):
colnames(tmp.dat)[ncol(tmp.dat)] <- "dv"
tmp.lm <- lm(as.formula(str_c("dv ~ ", rh2)), data = tmp.dat)
Anova(tmp.lm, type = type)
}
}
ez.glm <- function(id, dv, data, between = NULL, within = NULL, covariate = NULL, fun.aggregate = NULL, type = 3, ..., print.formula = FALSE) {
if (is.null(between) & is.null(within)) stop("Either between or within need to be non-NULL!")
if (!is.null(covariate)) covariate <- str_c(covariate, collapse = "+")
#browser()
rh <- if (!is.null(between) || !is.null(covariate)) str_c(if (!is.null(between)) str_c(between, collapse = " * ") else NULL, covariate, sep = " + ") else "1"
error <- str_c(" + Error(", id, if (!is.null(within)) "/" else "", str_c(within, collapse = " * "), ")")
formula <- str_c(dv, " ~ ", rh, error)
if (print.formula) message(str_c("Formula send to aov.car: ", formula))
aov.car(formula = as.formula(formula), data = data, fun.aggregate = fun.aggregate, type = type, ...)
}
univariate <- function(object) {
if (all(class(object) == c("anova", "data.frame"))) return(object)
# This function is basically a cropped copy of car::summary.Anova.mlm written by John Fox returning the output as a list (instead of printing it).
GG <- function(SSPE, P){ # Greenhouse-Geisser correction
p <- nrow(SSPE)
if (p < 2) return(NA)
lambda <- eigen(SSPE %*% solve(t(P) %*% P))$values
lambda <- lambda[lambda > 0]
((sum(lambda)/p)^2)/(sum(lambda^2)/p)
}
HF <- function(gg, error.df, p){ # Huynh-Feldt correction
((error.df + 1)*p*gg - 2)/(p*(error.df - p*gg))
}
mauchly <- function (SSD, P, df) {
# most of this function borrowed from stats:::mauchly.test.SSD
if (nrow(SSD) < 2) return(c(NA, NA))
Tr <- function (X) sum(diag(X))
p <- nrow(P)
I <- diag(p)
Psi <- t(P) %*% I %*% P
B <- SSD
pp <- nrow(SSD)
U <- solve(Psi, B)
n <- df
logW <- log(det(U)) - pp * log(Tr(U/pp))
rho <- 1 - (2 * pp^2 + pp + 2)/(6 * pp * n)
w2 <- (pp + 2) * (pp - 1) * (pp - 2) * (2 * pp^3 + 6 * pp^2 +
3 * p + 2)/(288 * (n * pp * rho)^2)
z <- -n * rho * logW
f <- pp * (pp + 1)/2 - 1
Pr1 <- pchisq(z, f, lower.tail = FALSE)
Pr2 <- pchisq(z, f + 4, lower.tail = FALSE)
pval <- Pr1 + w2 * (Pr2 - Pr1)
c(statistic = c(W = exp(logW)), p.value = pval)
}
nterms <- length(object$terms)
error.df <- object$error.df
table <- matrix(0, nterms, 6)
table2 <- matrix(0, nterms, 4)
table3 <- matrix(0, nterms, 2)
rownames(table3) <- rownames(table2) <- rownames(table) <- object$terms
colnames(table) <- c("SS", "num Df", "Error SS", "den Df", "F", "Pr(>F)")
colnames(table2) <- c("GG eps", "Pr(>F[GG])", "HF eps", "Pr(>F[HF])")
colnames(table3) <- c("Test statistic", "p-value")
#browser()
for (term in 1:nterms){
SSP <- object$SSP[[term]]
SSPE <- object$SSPE[[term]]
P <- object$P[[term]]
p <- ncol(P)
PtPinv <- solve(t(P) %*% P)
gg <- GG(SSPE, P)
table[term, "SS"] <- sum(diag(SSP %*% PtPinv))
table[term, "Error SS"] <- sum(diag(SSPE %*% PtPinv))
table[term, "num Df"] <- object$df[term] * p
table[term, "den Df"] <- error.df * p
table[term, "F"] <- (table[term, "SS"]/table[term, "num Df"])/
(table[term, "Error SS"]/table[term, "den Df"])
table[term, "Pr(>F)"] <- pf(table[term, "F"], table[term, "num Df"],
table[term, "den Df"], lower.tail=FALSE)
table2[term, "GG eps"] <- gg
table2[term, "HF eps"] <- HF(gg, error.df, p)
table3[term,] <- mauchly(SSPE, P, object$error.df)
}
results <- list(anova = table)
table3 <- na.omit(table3)
if (nrow(table3) > 0){
table2[,"Pr(>F[GG])"] <- pf(table[,"F"], table2[,"GG eps"]*table[,"num Df"],
table2[,"GG eps"]*table[,"den Df"], lower.tail=FALSE)
table2[,"Pr(>F[HF])"] <- pf(table[,"F"],
pmin(1, table2[,"HF eps"])*table[,"num Df"],
pmin(1, table2[,"HF eps"])*table[,"den Df"], lower.tail=FALSE)
table2 <- na.omit(table2)
if (any(table2[,"HF eps"] > 1))
warning("HF eps > 1 treated as 1")
attributes(table2)[["na.action"]] <- NULL
attributes(table3)[["na.action"]] <- NULL
results <- c(results, mauchly = list(table3), sphericity.correction = list(table2))
}
results
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.