Fits a generalised linear model of a response on one or more grouping
variables in any family, and reports an analysis of
deviance table, effect sizes, estimated marginal means and pairwise
comparisons.
Arguments
- data
A data frame, or anything inheriting from one, such as a
data.tableor a tibble.- response
Character. Name of the response column. For a binomial or quasi-binomial family it may be 0/1, logical, a proportion (with
weightsgiving the numbers of trials), or a factor or character column with exactly two observed values; the model is then for the second level (in C-locale order for a character column), and$notesnames it.- groups
Character vector. One or more grouping columns.
- family
A
familyobject, a family function, or the name of one as a character string. Defaultstats::gaussian().- interaction
FALSE(additive, the default),TRUE(full factorial), or a whole number giving the highest interaction order.- type
Character.
"II"(default) or"III"sums of squares. A model with aliased coefficients (an empty cell of the design, or collinear predictors) has no Type III tests; Type II tests are then computed instead, and$notes, the method and the table heading say so.- test_statistic
Character or
NULL. One of"LR","Wald"or"F", passed toAnova. WhenNULL(the default) it is chosen after fitting: an F test when the fitted model estimates its dispersion – the Gaussian, Gamma, inverse Gaussian, quasi, quasi-Poisson and quasi-binomial families, andMASS::negative.binomial(theta), whose coefficient table also uses t – and a likelihood ratio test when the dispersion is fixed (binomial, Poisson).- conf_level
Numeric in (0, 1). Level for every interval returned. Default
0.95.- ci_method
Character.
"profile"(default) or"wald"for the coefficient intervals. Both use the reference distribution of the coefficient table's p-values. For a family with a fixed dispersion (binomial, Poisson) the profile interval isstats::confint()'s, which cuts the signed-root deviance profile at normal quantiles. For a family that estimates its dispersion the same profile is cut atqt(., df.residual)instead, so that the interval agrees with the t test beside it; for the Gaussian identity model it equalsconfint(lm()). If profiling fails, Wald intervals are used, with a note. A bound the profile cannot reach (as under separation) isNA, also with a note.- vcov_type
Character.
"model"(default) or an HC type ("HC0"to"HC4"), which requires the sandwich package. The robust covariance is used by the coefficient table (with Wald intervals), the marginal means and the comparisons. The omnibus likelihood ratio and F tests are computed from the likelihood and cannot use it; withtest_statistic = "Wald"the omnibus test uses it too.$notessays which applies.- adjust
Character. Multiplicity adjustment for the pairwise comparisons, applied by emmeans. One of
"tukey","sidak","scheffe","dunnettx","bonferroni","holm","hochberg","hommel","BH","BY","fdr"or"none". Default"tukey".- posthoc
Logical. Compute pairwise comparisons. There are
choose(k, 2)of them, so this is worth turning off when the number of cells is large;$notesrecords that they were skipped. DefaultTRUE.- plots
Logical. Build ggplot2 objects. They are returned in
$plots, never drawn. DefaultTRUE.- weights
Optional character. Name of a numeric column of prior weights. Given as a column name rather than a vector so that it is subsetted with the data: a vector supplied by the caller is evaluated against the original frame and silently misaligns as soon as one row is dropped for missing values. Rows with weight zero contribute nothing to the fit; they are dropped before fitting and counted in
$n_removed. Whole-number weights (some above 1) on a count or 0/1 response are read as frequency weights, each row standing for that many identical observations: the robust covariance (vcov_type) and, for the Poisson families, the residual degrees of freedom are then those of the data expanded to one row per observation. Other weights (precision weights, or the trials behind a proportion) keep each row as one unit.- verbose
Logical. Emit progress through
message. DefaultFALSE.
Value
An anovakit_fit object, with $family (the
family object actually used) and $model_stats (AIC, BIC, the null
and residual deviances, and the residual degrees of freedom).
$anova has the columns term, sum_sq (F tests only),
df, statistic and p_value, in that order whatever
test_statistic. In an F table of a non-Gaussian family, as
car computes it, a term's sum_sq is its change in deviance
and the Residuals row holds the Pearson chi-square, from which the
dispersion the F statistic divides by is estimated.
$assumptions holds coefficients – the coefficient table,
with the intervals ci_method selects – and dispersion.
$effect_sizes depends on the family:
Gaussian: partial eta squared and partial omega squared for each term, from the F table's sums of squares whatever
test_statisticis. Partial omega squared is floored at 0, with a note. When the ANOVA table cannot be computed (a Type III table with an empty cell, say) the table is empty and a note says why.Any other family:
deviance_explained,1 - deviance / null deviance, andmcfadden_r2, McFadden's pseudo R squared1 - logLik(model) / logLik(intercept-only model). McFadden's measure is reported only for the binomial, Poisson and negative binomial families, whose log-likelihoods are probabilities; for a binomial response it is computed from the Bernoulli log-likelihood, so it is the same whether the data are given one row per trial or aggregated as proportions with trial weights (and for a 0/1 response it equals the deviance explained). For the Gamma, inverse Gaussian and quasi families it isNAwith a note: a density's log-likelihood changes with the units of the response, and a quasi family has none. The deviance explained is measured against the saturated model, so for binomial data it does depend on the aggregation.
Details
Type III sums of squares. When type = "III" the model is
fitted under sum-to-zero contrasts. This is the whole point: setting
options(contrasts = ) after a model has been fitted does not change
the contrasts stored on it, so car::Anova(type = 3) would silently
report simple effects at the reference level under the label "Type III".
Post-hoc. Marginal means and comparisons come from emmeans and are on the response scale. When the grouping variables enter the model additively (the default with more than one), they are reported for each factor on its own, averaged over the others; with an interaction they are made across the cells of the grid. With a log or logit link a comparison is a ratio (of means, or of odds); with any other non-identity link (inverse, probit, square root, ...) it is a difference between the marginal means on the response scale. Families that estimate their dispersion use t with the residual degrees of freedom, as the coefficient table does.
Separation. For binomial, quasi-binomial, Poisson, quasi-Poisson
and negative binomial families the fit is checked for groups whose fitted
probability is numerically 0 or 1 (or whose fitted rate is numerically 0),
where coefficients, Wald tests and comparisons are not identified;
$notes says so when it happens.
For binary responses see anova_bin, and for counts see
anova_count: both add family-specific diagnostics and effect
sizes that this general wrapper does not.
See also
anova_bin and anova_count, which add
family-specific diagnostics and effect sizes.
Examples
set.seed(42)
d <- data.frame(
A = factor(sample(c("a1", "a2"), 200, replace = TRUE)),
B = factor(sample(c("b1", "b2"), 200, replace = TRUE))
)
d$y <- 3 + 2 * (d$A == "a2") + (d$B == "b2") +
4 * (d$A == "a2") * (d$B == "b2") + rnorm(200)
# Type III tests, with the model fitted under sum-to-zero contrasts
fit <- anova_glm(d, "y", c("A", "B"), interaction = TRUE, type = "III")
fit$anova
#> term sum_sq df statistic p_value
#> 1 A 828.3928 1 924.0123 4.109856e-76
#> 2 B 378.7873 1 422.5099 8.435778e-51
#> 3 A:B 192.5110 1 214.7321 2.549481e-33
#> 4 Residuals 175.7173 196 NA NA
# The coefficient table, with profile-likelihood intervals by default
fit$assumptions$coefficients
#> term estimate se statistic p_value distribution
#> 1 (Intercept) 5.4973240 0.06790639 80.95444 1.359261e-152 t
#> 2 A1 -2.0641894 0.06790639 -30.39757 4.109856e-76 t
#> 3 B1 -1.3958190 0.06790639 -20.55505 8.435778e-51 t
#> 4 A1:B1 0.9950827 0.06790639 14.65374 2.549481e-33 t
#> conf_low conf_high ci_method
#> 1 5.3634030 5.631245 profile
#> 2 -2.1981104 -1.930268 profile
#> 3 -1.5297399 -1.261898 profile
#> 4 0.8611617 1.129004 profile
# A family may be given as a string, as stats::glm() allows. For a binary
# response anova_bin() is usually the better entry point.
d$hit <- rbinom(200, 1, plogis(-0.5 + 1.2 * (d$A == "a2")))
bin <- anova_glm(d, "hit", "A", family = "binomial", plots = FALSE)
bin$anova
#> term df statistic p_value
#> 1 A 1 22.84952 1.751931e-06
bin$effect_sizes
#> measure estimate
#> 1 deviance_explained 0.08270479
#> 2 mcfadden_r2 0.08270479
# Heteroskedasticity-consistent standard errors, which flow through to the
# marginal means and the comparisons
anova_glm(d, "y", "A", vcov_type = "HC3", plots = FALSE)$emmeans
#> A estimate se df conf_low conf_high
#> 1 a1 3.365595 0.1004602 198 3.167486 3.563704
#> 2 a2 7.583053 0.2482866 198 7.093427 8.072679