# How does one do a Type-III SS ANOVA in R with contrast codes?

Please provide R code which allows one to conduct a between-subjects ANOVA with -3, -1, 1, 3 contrasts. I understand there is a debate regarding the appropriate Sum of Squares (SS) type for such an analysis. However, as the default type of SS used in SAS and SPSS (Type III) is considered the standard in my area. Thus I would like the results of this analysis to match perfectly what is generated by those statistics programs. To be accepted an answer must directly call aov(), but other answers may be voted up (espeically if they are easy to understand/use).

sample.data <- data.frame(IV=rep(1:4,each=20),DV=rep(c(-3,-3,1,3),each=20)+rnorm(80))


Edit: Please note, the contrast I am requesting is not a simple linear or polynomial contrast but is a contrast derived by a theoretical prediction, i.e. the type of contrasts discussed by Rosenthal and Rosnow.

• I understand that you need Type III sum, but this (stats.ox.ac.uk/pub/MASS3/Exegeses.pdf) article is a good read. It illustrates some interesting points. Commented Nov 15, 2010 at 19:03
• Concerning your question you might be interested in the following discussion: stats.stackexchange.com/questions/60362/… The choice between ANOVA type I, II, and III is not as easy as it seems.
– phx
Commented Jun 8, 2014 at 19:15
• Upvoted your question as useful in that it provoked several learned responses, but I also note that you agreed with the respondent who basically said that the premise of the question was incorrect. I hope I am summarizing StaGuy's position as saying defined contrasts were by definition "type I" and discussion of other types only became relevant when assessing partial regression statistics, presumably most important when letting "the machine do the driving" using automated methods.
– DWin
Commented May 11, 2015 at 18:10
• @DWin: I'm not sure I entirely follow you. One can legitimately use other types of SS without letting the 'machine do the driving' (at least as I understand that phrase). I might be a bit rusty here, but if memory serves, other types can be relevant when not using partial regression. For example, Type III SS doesn't partial the main effects out of the interaction. The distinction between the types matters there precisely because Type III doesn't partial whereas Type I does. The problem as stated included only a single contrast and therefore the distinction between types of SS was/is moot. Commented May 11, 2015 at 18:37
• My understanding was that the rationale given by SAS for choosing type III SSS (and this seems to be why people thinks that type-III is preferred) is that it better supports the backward and forward selection process.
– DWin
Commented May 11, 2015 at 19:18

Type III sum of squares for ANOVA are readily available through the Anova() function from the car package.

Contrast coding can be done in several ways, using C(), the contr.* family (as indicated by @nico), or directly the contrasts() function/argument. This is detailed in §6.2 (pp. 144-151) of Modern Applied Statistics with S (Springer, 2002, 4th ed.). Note that aov() is just a wrapper function for the lm() function. It is interesting when one wants to control the error term of the model (like in a within-subject design), but otherwise they both yield the same results (and whatever the way you fit your model, you still can output ANOVA or LM-like summaries with summary.aov or summary.lm).

I don't have SPSS to compare the two outputs, but something like

> library(car)
> sample.data <- data.frame(IV=factor(rep(1:4,each=20)),
DV=rep(c(-3,-3,1,3),each=20)+rnorm(80))
> Anova(lm1 <- lm(DV ~ IV, data=sample.data,
contrasts=list(IV=contr.poly)), type="III")
Anova Table (Type III tests)

Response: DV
Sum Sq Df F value    Pr(>F)
(Intercept)  18.08  1  21.815  1.27e-05 ***
IV          567.05  3 228.046 < 2.2e-16 ***
Residuals    62.99 76
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


is worth to try in first instance.

About factor coding in R vs. SAS: R considers the baseline or reference level as the first level in lexicographic order, whereas SAS considers the last one. So, to get comparable results, either you have to use contr.SAS() or to relevel() your R factor.

• I don't think this answer uses the -3,-1,1,3 contrast I specified nor does it seem to provide a 1 df test of the contrast. Commented Nov 15, 2010 at 21:33
• @drknexus Yes, you're right. Wrote too quickly. Something like Anova(lm(DV ~ C(IV, c(-3,-1,1,3),1), data=sample.data), type="III") should be better. Please let me know if this ok with you.
– chl
Commented Nov 15, 2010 at 22:23
• Thanks! That looks okay I'll validate it against SPSS tomorrow and get back to you. Commented Nov 15, 2010 at 22:35
• BTW, have a look at the ez package (cran.r-project.org/web/packages/ez/index.html) for wrapping the Anova code... Commented Nov 16, 2010 at 12:45
• @drknexus: If only there were a feature request & issues submission page for ez... github.com/mike-lawrence/ez/issues :) Commented Sep 15, 2011 at 10:50

This may look like a bit of self-promotion (and I suppose it is). But I developed an lsmeans package for R (available on CRAN) that is designed to handle exactly this sort of situation. Here is how it works for your example:

> sample.data <- data.frame(IV=rep(1:4,each=20),DV=rep(c(-3,-3,1,3),each=20)+rnorm(80))
> sample.aov <- aov(DV ~ factor(IV), data = sample.data)

> library("lsmeans")
> (sample.lsm <- lsmeans(sample.aov, "IV"))
IV    lsmean        SE df   lower.CL  upper.CL
1 -3.009669 0.2237448 76 -3.4552957 -2.564043
2 -3.046072 0.2237448 76 -3.4916980 -2.600445
3  1.147080 0.2237448 76  0.7014539  1.592707
4  3.049153 0.2237448 76  2.6035264  3.494779

> contrast(sample.lsm, list(mycon = c(-3,-1,1,3)))
contrast estimate       SE df t.ratio p.value
mycon    22.36962 1.000617 76  22.356  <.0001


You could specify additional contrasts in the list if you like. For this example, you'll get the same results with the built-in linear polynomial contrast:

> con <- contrast(sample.lsm, "poly")
> con
contrast   estimate        SE df t.ratio p.value
linear    22.369618 1.0006172 76  22.356  <.0001
quadratic  1.938475 0.4474896 76   4.332  <.0001
cubic     -6.520633 1.0006172 76  -6.517  <.0001


To confirm this, note that the "poly" specification directs it to call poly.lsmc, which produces these results:

> poly.lsmc(1:4)
1     -3         1    -1
2     -1        -1     3
3      1        -1    -3
4      3         1     1


If you wish to do a joint test of several contrasts, use the test function with joint = TRUE. For example,

> test(con, joint = TRUE)


This will produce a "type III" test. Unlike car::Anova(), it will do it correctly regardless of the contrast coding used in the model-fitting stage. This is because the linear functions being tested are specified directly rather than implicitly via model reduction. An additional feature is that a case where the contrasts being tested are linearly dependent is detected, and the correct test statistic and degrees of freedom are produced.

You may want to have a look at this blog post:

Obtaining the same ANOVA results in R as in SPSS - the difficulties with Type II and Type III sums of squares

(Spoiler: add options(contrasts=c("contr.sum", "contr.poly")) at the beginning of your script)

• Note the additional information on joint testing in rvl's answer. Commented Jul 24, 2017 at 20:10

When you are doing contrasts, you are doing a specific, stated linear combination of cell means within the context of the appropriate error term. As such, the concept of "Type of SS" is not meaningful with contrasts. Each contrast is essentially the first effect using a Type I SS. "Type of SS" has to do with what is partialled out or accounted for by the other terms. For contrasts, nothing is partialled out or accounted for. The contrast stands by itself.

• You are absolutely right. Commented Jan 31, 2013 at 0:36

The fact that type III tests are used in your place of work is the weakest of reasons to keep using them. SAS has done major damage to statistics in this regard. Bill Venables' exegesis, referenced above, is a great resource on this. Just say no to type III; it's based on a faulty notion of balance and has lower power because of silly weighting of cells in the imbalanced case.

A more natural and less error-prone way to get general contrasts, and to be able to describe what you did, is provided by the R rms package contrast.rms function. Contrasts can be very complex but to the user are very simple because they are stated in terms of differences in predictive values. Tests and simultaneous contrasts are supported. This handles nonlinear regression effects, nonlinear interaction effects, partial contrasts, all kinds of things.

• That's all fine and good for you as an established person of repute to say. Others don't have clout to disagree with reviewers. Since interpretations of the stats differ, you'd be asking new folk to stand on principle and incur an unreasonable cost. I say that as someone who died my share of times on top of this (and similar) hills. IMO change on this front is the responsibility of gatekeepers, i.e. editors and reviewers. Commented May 5, 2018 at 13:40
• People who are really good with data have a wide choice of jobs and may have the option to work in areas where their skills and opinions are respected. Commented May 5, 2018 at 14:43
• ... and that's what I do now. But people who are arriving at this question won't frequently be of that class. Just as I wasn't 7 years ago. I only advocate for a bit of empathy for the novice and their circumstances. Commented May 5, 2018 at 15:53

Try the Anova command in the car library. Use the type="III" argument, as it defaults to type II. For example:

library(car)
mod <- lm(conformity ~ fcategory*partner.status, data=Moore, contrasts=list(fcategory=contr.sum, partner.status=contr.sum))
Anova(mod, type="III")

• I know Moore is in the car library, but When sample data is provided it is easier for the question asker to understand your response if you use the sample data. Commented Nov 15, 2010 at 21:23

Also self-promoting, I wrote a function for exactly this: https://github.com/samuelfranssens/type3anova

Install as follows:

library(devtools)
install_github(samuelfranssens/type3anova)
library(type3anova)

sample.data <- data.frame(IV=rep(1:4,each=20),DV=rep(c(-3,-3,1,3),each=20)+rnorm(80))

type3anova(lm(DV ~ IV, data = sample.data))


You will also need to have the car package installed.

• How would you apply this to the contrasts part of the question? Commented May 5, 2018 at 13:42
• Apologies, I didn't read the question properly. My function will only simplify carrying out type III Anova. Like StatGuy above, I don't see where SS comes into play when testing specific contrasts. Commented May 6, 2018 at 10:38
• Is there any way that we can use the TukeyHSD function with the output from car::Anova (type3)? I need to find the p values for the contrast. At the time, TukeyHSD only accepts the output from aov(which calculates only the type I) but not from car::Anova Commented Oct 21, 2022 at 12:12