Skip to contents

Why the Question Arises

In a factorial analysis of variance with equal cell sizes, the effects are orthogonal: the sum of squares for each main effect and interaction is the same no matter what else is in the model, and the effect sums of squares add up to the model sum of squares. There is one partition and no choice to make.

The moment the cell sizes are unequal, or a continuous covariate enters the model, the effects are no longer orthogonal. Each effect now shares variation with the others, so its sum of squares depends on what it is adjusted for. The “types” of sums of squares (Type I, Type II, and Type III, in the labeling that the SAS GLM procedure made standard) are nothing more than different conventions for that adjustment. They agree for balanced data and can disagree, sometimes sharply, for unbalanced data.

Analysis of covariance is nonorthogonal essentially by construction: even with equal numbers per group, the covariate is generally not orthogonal to the grouping factor, so the covariate-adjusted comparison is already an exercise in choosing what each effect is adjusted for.

A Short History in Psychology

The problem of unequal subclass numbers was posed by Yates (1934). It reached applied psychology through Overall and Spiegel (1969), who laid out three “methods” of analyzing nonorthogonal data that correspond, in order, to what are now called Type III, Type II, and Type I sums of squares. Their paper set off an extended methodological exchange: Appelbaum and Cramer (1974) clarified which hypotheses each method actually tests and warned against choosing a method for convenience rather than for the question, and Carlson and Timm (1974) and Herr and Gaebelein (1978) carried the argument further. Nelder (1977) framed the issue in terms of the principle of marginality, the reasoning behind Type II. Maxwell, Delaney, and Kelley (2027, Chapter 7) synthesize this literature from the model comparison perspective, which is the cleanest way to see what the types are, and the framing used here.

A Sum of Squares Is a Model Comparison

In the model comparison perspective, every sum of squares is the same object: the reduction in error when a fuller model replaces a more restricted one,

SS(effect)=ErestrictedEfull, \mathrm{SS}(\text{effect}) \;=\; E_{\mathrm{restricted}} - E_{\mathrm{full}},

where EE is the error (residual) sum of squares of a model. The effect is the set of parameters that the full model has and the restricted model does not. A “type” is simply a rule for which full and restricted pair to compare for each effect. Once the two models are written down, there is nothing mysterious left; the disagreement among the types is a disagreement about which models answer the question.

Type I, Type II, and Type III

Consider a two-factor design with factors AA and BB and their interaction A:BA{:}B. Writing SS(XZ)\mathrm{SS}(X \mid Z) for the effect of XX adjusted for the terms in ZZ:

  • Type I (sequential). Each term is adjusted only for the terms entered before it: SS(A)\mathrm{SS}(A), then SS(BA)\mathrm{SS}(B \mid A), then SS(A:BA,B)\mathrm{SS}(A{:}B \mid A, B). The pieces add to the model sum of squares, but the answer depends on the order the terms are listed. Type I is the right choice only when the terms have a genuine a priori ordering, as when a covariate is entered before the factor it adjusts.
  • Type II. Each term is adjusted for every other term that does not contain it, honoring the principle of marginality: SS(AB)\mathrm{SS}(A \mid B), SS(BA)\mathrm{SS}(B \mid A), SS(A:BA,B)\mathrm{SS}(A{:}B \mid A, B). Main effects are not adjusted for the interaction. Type II is the most powerful option when the interaction is absent, and it does not depend on how the factors are coded.
  • Type III. Each term is adjusted for all other terms, including the higher-order terms that contain it: SS(AB,A:B)\mathrm{SS}(A \mid B, A{:}B), SS(BA,A:B)\mathrm{SS}(B \mid A, A{:}B). This is the SAS GLM default and the default of . The main-effect tests concern the unweighted marginal means, which is why they require sum-to-zero contrasts () to test the intended hypothesis; with R’s default treatment contrasts a naive Type III main-effect test is not that hypothesis.

A Worked Unbalanced Factorial

The types diverge only for nonorthogonal data, so the demonstration needs an unbalanced design. The cells below have deliberately unequal sizes.

set.seed(113)
cell <- function(a, b, n, mu) data.frame(A = a, B = b, y = rnorm(n, mu, 1))
d <- rbind(
  cell("a1", "b1",  8, 10.0), cell("a1", "b2",  5, 11.0), cell("a1", "b3", 12, 10.5),
  cell("a2", "b1",  6, 10.8), cell("a2", "b2", 11, 11.2), cell("a2", "b3",  4, 12.0)
)
d$A <- factor(d$A)
d$B <- factor(d$B)
table(d$A, d$B)
#>     
#>      b1 b2 b3
#>   a1  8  5 12
#>   a2  6 11  4

DMAR’s factorial_anova() computes all three types by model comparison in base R, choosing the type through an argument. It reports each effect’s sum of squares, its test, and partial and partial with confidence intervals, and it notes the type beneath the table.

factorial_anova(y ~ A * B, data = d, ss_type = 1)   # sequential
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 2 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
effect SS df F_value p_value eta_squared_partial eta_squared_partial_lower eta_squared_partial_upper omega_squared_partial omega_squared_partial_lower omega_squared_partial_upper
A 8.74 1 7.55 0.0090 0.159 0.00971 0.332 0.125 0.00971 0.332
B 14.2 2 6.11 0.0048 0.234 0.0259 0.394 0.182 0.0259 0.394
A:B 1.47 2 0.636 0.5345 0.0308 0 0.146 0 0 0.146
Residuals 46.3 40 NA NA NA NA NA NA NA NA

Sum of squares: Type I Confidence level: 95%

factorial_anova(y ~ A * B, data = d, ss_type = 2)
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 2 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
effect SS df F_value p_value eta_squared_partial eta_squared_partial_lower eta_squared_partial_upper omega_squared_partial omega_squared_partial_lower omega_squared_partial_upper
A 7.4 1 6.39 0.0155 0.138 0.0041 0.31 0.105 0.0041 0.31
B 14.2 2 6.11 0.0048 0.234 0.0259 0.394 0.182 0.0259 0.394
A:B 1.47 2 0.636 0.5345 0.0308 0 0.146 0 0 0.146
Residuals 46.3 40 NA NA NA NA NA NA NA NA

Sum of squares: Type II Confidence level: 95%

factorial_anova(y ~ A * B, data = d, ss_type = 3)
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 2 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
effect SS df F_value p_value eta_squared_partial eta_squared_partial_lower eta_squared_partial_upper omega_squared_partial omega_squared_partial_lower omega_squared_partial_upper
A 7.64 1 6.6 0.0141 0.142 0.00504 0.314 0.108 0.00504 0.314
B 14.7 2 6.34 0.0041 0.241 0.0292 0.4 0.188 0.0292 0.4
A:B 1.47 2 0.636 0.5345 0.0308 0 0.146 0 0 0.146
Residuals 46.3 40 NA NA NA NA NA NA NA NA

Sum of squares: Type III Confidence level: 95%

Type I is sequential, so listing the factors in the other order changes it, while Type II and Type III do not depend on the order:

factorial_anova(y ~ A * B, data = d, ss_type = 1)$SS[1:3]  # A entered first
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 2 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1]  8.743295 14.159731  1.474433
factorial_anova(y ~ B * A, data = d, ss_type = 1)$SS[1:3]  # B first: different
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 2 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1] 15.500188  7.402838  1.474433

The main-effect sums of squares differ across the three types here precisely because the cells are unequal. The interaction sum of squares is the same under all three (it is the highest-order term, so nothing contains it), a useful check.

factorial_anova() does not use the car package, but it agrees with car::Anova() to numerical precision. Type III main-effect tests need sum-to-zero contrasts, which factorial_anova() applies internally and which car::Anova() needs on the refit model:

fit_sum <- lm(y ~ A * B, data = d,
              contrasts = list(A = contr.sum, B = contr.sum))
car::Anova(fit_sum, type = 3)[c("A", "B", "A:B"), "Sum Sq"]
#> [1]  7.641891 14.692503  1.474433
factorial_anova(y ~ A * B, data = d, ss_type = 3)$SS[1:3]   # matches
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 2 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1]  7.641891 14.692503  1.474433

How factorial_anova() Computes the Types

Each sum of squares is a model comparison, and every model in the comparison is an ordinary least squares fit to a subset of the columns of one model matrix. factorial_anova() builds the full model matrix once, with sum-to-zero contrasts, and for each effect it takes the residual sum of squares (through the QR decomposition) of the fit that keeps the intercept plus a chosen set of terms. The sum of squares for the effect is the restricted residual sum of squares minus the full residual sum of squares. No separate analysis of variance routine is needed, and the computation does not use the car package.

The three types differ only in which columns the restricted and full models share:

  • Type I keeps the terms listed before the effect versus those terms plus the effect, stepping through the formula in order.
  • Type II keeps every term that does not contain the effect versus those terms plus the effect. “Contains” is the marginality relation: the term A:B contains A and B, so a main effect is adjusted for the other main effects but not for the interactions built on it.
  • Type III starts from the full model and drops only the effect’s own columns, leaving every other term in place, including the interactions that contain the effect. Sum-to-zero contrasts make this the test of the unweighted marginal means, and factorial_anova() applies them internally so the user does not have to.

The marginality relation is what makes Types II and III general. The same rule that adjusts a main effect for the interaction containing it in a two-factor design adjusts it for the two-way and three-way interactions in a three-factor design, and onward to any number of factors and any interaction order. The values agree with car::Anova() from one-way through three-way unbalanced designs, which the package tests verify. A three-way check:

set.seed(113)
g <- expand.grid(A = factor(1:2), B = factor(1:2), C = factor(1:3))
g <- g[rep(seq_len(nrow(g)), c(6, 4, 5, 7, 3, 8, 6, 5, 4, 7, 5, 6)), ]  # unbalanced
g$y <- rnorm(nrow(g)) + as.numeric(g$A) + 0.5 * as.numeric(g$B)
gs <- lm(y ~ A * B * C, data = g,
         contrasts = list(A = contr.sum, B = contr.sum, C = contr.sum))

effs <- c("A", "B", "C", "A:B", "A:C", "B:C", "A:B:C")
factorial_anova(y ~ A * B * C, data = g, ss_type = 3)$SS[1:7]  # DMAR
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 10
#> of the effect size confidence intervals; the affected lower limits were clamped
#> to 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1] 13.71618522  8.32810994  1.06755478  0.06162124  0.32821820  2.47361380
#> [7]  1.02265698
car::Anova(gs, type = 3)[effs, "Sum Sq"]                        # matches
#> [1] 13.71618522  8.32810994  1.06755478  0.06162124  0.32821820  2.47361380
#> [7]  1.02265698

Balanced Data: The Types Coincide

With equal cell sizes the effects are orthogonal and the question disappears.

set.seed(113)
db <- do.call(rbind, lapply(c("a1", "a2"), function(a)
  do.call(rbind, lapply(c("b1", "b2", "b3"), function(b)
    data.frame(A = a, B = b, y = rnorm(8, 10.5, 1))))))
db$A <- factor(db$A); db$B <- factor(db$B)

factorial_anova(y ~ A * B, data = db, ss_type = 1)$SS[1:3]   # Type I
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 6 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1] 0.06622407 2.54191761 1.35217335
factorial_anova(y ~ A * B, data = db, ss_type = 2)$SS[1:3]   # Type II
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 6 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1] 0.06622407 2.54191761 1.35217335
factorial_anova(y ~ A * B, data = db, ss_type = 3)$SS[1:3]   # Type III
#> Warning: The noncentral F lower-limit clamp in conf_limits_ncf() fired for 6 of
#> the effect size confidence intervals; the affected lower limits were clamped to
#> 0. See ?conf_limits_ncf for the meaning of the clamp.
#> [1] 0.06622407 2.54191761 1.35217335

The three sets of sums of squares match to numerical precision. This is the deeper point: the type matters only when the design is nonorthogonal, so a balanced design sidesteps the whole controversy.

ANCOVA Is Nonorthogonal by Construction

A covariate makes the design nonorthogonal even with equal group sizes, so the covariate-adjusted treatment test is already a choice of adjustment. DMAR’s ancova() reports the covariate-adjusted (Type III, equivalently Type II for a single grouping factor) effect, and records the sum-of-squares type it used.

res <- ancova(outcome = "iq_8", treatment = "treatment",
              covariates = "iq_pre", data = pygmalion)
res[res$term %in% c("F_value", "df_1", "df_2", "p_value",
                    "sum_of_squares_type"), ]
term value
F_value 5.38
df_1 1
df_2 307
p_value 0.0210
sum_of_squares_type 3

Confidence level: 95%

The adjusted matches what car::Anova() returns at Type III (and Type II, which coincides here because there is a single factor).

dd <- pygmalion[stats::complete.cases(
  pygmalion[, c("iq_8", "treatment", "iq_pre")]), ]
dd$treatment <- factor(dd$treatment)
fit_anc <- lm(iq_8 ~ treatment + iq_pre, data = dd,
              contrasts = list(treatment = contr.sum))
car::Anova(fit_anc, type = 3)["treatment", "F value"]
#> [1] 5.382682
res$value[res$term == "F_value"]
#> [1] 5.382682

For a one-way ANCOVA there is nothing to toggle: the covariate-adjusted test is the same under Types II and III. The choice of type begins to matter only when a second factor or an interaction enters, which is the multifactor case above.

The Multivariate Case: MANOVA and MANCOVA

When the outcome is a vector of correlated dependent variables, the scalar sums of squares become sum of squares and cross-products (SSCP) matrices: a hypothesis matrix 𝐇\mathbf{H} and an error matrix 𝐄\mathbf{E}. The type logic is unchanged; it determines which model comparison forms 𝐇\mathbf{H} for each effect. The omnibus test is then a function of the eigenvalues of 𝐇𝐄1\mathbf{H}\mathbf{E}^{-1}, reported as Wilks’ lambda, Pillai’s trace, the Hotelling-Lawley trace, or Roy’s largest root. They agree when the effect is one-dimensional and diverge as it spreads across dimensions; Pillai’s trace is the most robust to assumption violations.

DMAR’s manova_split_plot() carries out a mixed-design multivariate analysis through car::Anova(), reports all four statistics, and defaults to Type III with an ss_type argument for Type II. Adding covariates turns the analysis into MANCOVA, with 𝐇\mathbf{H} and 𝐄\mathbf{E} formed after adjustment for the covariates; the same type considerations apply.

Recommendations

The model comparison perspective dissolves most of the controversy: state the full and restricted models you intend to compare, and the sum of squares follows. With that in hand:

  • For a balanced design, the types coincide; report any of them.
  • When there is no interaction, Type II is the most powerful test of the main effects and does not depend on the coding of the factors.
  • Type III is the common reporting default and corresponds to hypotheses about unweighted marginal means, but it requires sum-to-zero contrasts and is an awkward hypothesis for a main effect that is part of a real interaction.
  • When an interaction is present, the marginal main-effect tests of any type are usually the wrong focus; examine the interaction and the simple effects instead (Maxwell, Delaney, and Kelley, 2027).

In DMAR, factorial_anova() carries this out for a between-subjects design: it computes the chosen type by model comparison in base R and reports each effect with its partial and partial confidence intervals. ancova() and manova_split_plot() cover the covariate-adjusted and multivariate cases.

The recurring theme, from Overall and Spiegel (1969) through Appelbaum and Cramer (1974) to the present, is that the type should follow from the question, not the other way around.

References

Appelbaum, M. I., & Cramer, E. M. (1974). Some problems in the nonorthogonal analysis of variance. Psychological Bulletin, 81(6), 335–343.

Carlson, J. E., & Timm, N. H. (1974). Analysis of nonorthogonal fixed-effects designs. Psychological Bulletin, 81(9), 563–570.

Herr, D. G., & Gaebelein, J. (1978). Nonorthogonal analysis of variance. Psychological Bulletin, 85(1), 207–216.

Maxwell, S. E., Delaney, H. D., & Kelley, K. (2027). Designing experiments and analyzing data: A model comparison perspective (4th ed.). Routledge. (See Chapter 7 on higher-order designs.)

Nelder, J. A. (1977). A reformulation of linear models. Journal of the Royal Statistical Society, Series A, 140(1), 48–77.

Overall, J. E., & Spiegel, D. K. (1969). Concerning least squares analysis of experimental data. Psychological Bulletin, 72(5), 311–322.

Searle, S. R. (1987). Linear models for unbalanced data. Wiley.

Yates, F. (1934). The analysis of multiple classifications with unequal numbers in the different classes. Journal of the American Statistical Association, 29(185), 51–66.