In this note I want to highlight an issue that occurs when you are
using the emmeans
package to perform a Scheffe test.
I’m going to illustrate the issue with an analysis on the following data:
options(contrasts=c("contr.sum","contr.poly")) # IMPORTANT
options(digits=6)
a <- 5
n <- 10
N <- a*n
y.bar <- 0.9*c(-1/2,-1/2,0,0,1)
set.seed(143)
score <- 100+5*(rep(x=y.bar,each=n) + rnorm(N,0,1))
group <- factor(x=rep(x=seq(1,a),each=n),labels="g",ordered=F)
df0 <- data.frame(group,score)
summary(df0)
## group score
## g1:10 Min. : 88.1
## g2:10 1st Qu.: 97.0
## g3:10 Median :101.1
## g4:10 Mean :101.2
## g5:10 3rd Qu.:105.7
## Max. :112.8
boxplot(score~group,data=df0)
First I will do a plain-vanilla ANOVA.
aov.01 <- aov(score~group,data=df0)
summary(aov.01)
## Df Sum Sq Mean Sq F value Pr(>F)
## group 4 200 50.1 1.63 0.18
## Residuals 45 1382 30.7
Next, we will perform four orthogonal contrasts using the following weights.
c1 <- c(-1/4,-1/4,-1/4,-1/4,1)
c2 <- c(-1/2,-1/2,1/2,1/2,0)
c3 <- c(-1,1,0,0,0)
c4 <- c(0,0,-1,1,0)
library(MASS)
cMat <- ginv(rbind(c1,c2,c3,c4)) # our coding matrix
First, I will use the aov
and split
commands.
contrasts(df0$group) <- cMat
contrasts(df0$group) # our coding matrix
## [,1] [,2] [,3] [,4]
## g1 -0.2 -5.00000e-01 -5.00000e-01 1.11041e-17
## g2 -0.2 -5.00000e-01 5.00000e-01 3.63225e-17
## g3 -0.2 5.00000e-01 -7.10914e-17 -5.00000e-01
## g4 -0.2 5.00000e-01 -8.11958e-17 5.00000e-01
## g5 0.8 1.35912e-17 -5.34703e-17 -2.80000e-17
aov.02 <- aov(score~group,data=df0) # re-do anova
summary(aov.02,split=list(group=list(c1=1,c2=2,c3=3,c4=4)))
## Df Sum Sq Mean Sq F value Pr(>F)
## group 4 200 50.1 1.63 0.183
## group: c1 1 152 151.8 4.94 0.031 *
## group: c2 1 44 43.6 1.42 0.240
## group: c3 1 5 4.9 0.16 0.691
## group: c4 1 0 0.0 0.00 0.982
## Residuals 45 1382 30.7
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
coef(aov.02)
## (Intercept) group1 group2 group3 group4
## 101.1590132 4.3553954 2.0878661 -0.9926173 0.0577542
Next, I will perform the contrasts using emmeans
. Notice
that the p values are the same as those in the ANOVA. If the contrasts
were planned, then only contrast c1
would be significant.
Also note that the values of the contrasts (in the estimate
column) are the same as the coefficients/alpha’s from our linear
model.
library(emmeans)
aov.em <- emmeans(aov.02,specs="group")
con <- contrast(aov.em,method=list(c1,c2,c3,c4))
summary(con,adjust="none")
Now let’s consider the case where the contrasts were performed after looking at the data. The Scheffe test can be performed by recalculating the critical value of F that is used to reject the null hypothesis. Here is the critical value of F used in the omnibus test:
a <- 5
n <- 10
N <- a*n
alpha <- .05
( F.omnibus <- qf(1-alpha,df1=(a-1),df2=N-a) )
## [1] 2.57874
The critical value of F for the Scheffe test is obtained by
multiplying F.omnibus
by the degrees of freedom for
group
:
( F.Scheffe <- F.omnibus * (a-1))
## [1] 10.315
If c1
was post-hoc, and we used the Scheffe test to
control Type I error at \(\alpha=0.05\), then contrast
c1
would not be significant because the observed F for that
contrast, 4.94, is less than the Scheffe critical F of 10.31.
Next we repeat the Scheffe test using the emmeans
package. The commands in emmeans
perform the Scheffe test
by adjusting the p values, rather than adjusting the critical value of t
or F used to reject the null hypothesis. Nevertheless, the conclusions
about the post-hoc contrasts are the same: none of the contrasts are
significant when we use the Scheffe adjustment.
library(emmeans)
aov.em <- emmeans(aov.02,specs="group")
contrast(aov.em,method=list(c1,c2,c3,c4),adjust="scheffe")
## contrast estimate SE df t.ratio p.value
## c(-0.25, -0.25, -0.25, -0.25, 1) 4.3554 1.96 45 2.223 0.3096
## c(-0.5, -0.5, 0.5, 0.5, 0) 2.0879 1.75 45 1.191 0.8394
## c(-1, 1, 0, 0, 0) -0.9926 2.48 45 -0.400 0.9968
## c(0, 0, -1, 1, 0) 0.0578 2.48 45 0.023 1.0000
##
## P value adjustment: scheffe method with rank 4
I want to call your attention to the last line in the output, which
says the p values have been adjusted with the
"scheffe method with rank 4"
. We will return to this point
in a moment.
In the previous example we used the Scheffe test to evaluate three
post-hoc contrasts. However, let’s suppose we had conducted only the
first contrast (c1
) and never considered the other two. Our
analysis using the aov
split
command would
have been something like the following:
contrasts(df0$group) <- c1 # define our 1 contrast
aov.03 <- aov(score~group,data=df0) # re-do anova
summary(aov.03,split=list(group=list(c1=1)))
## Df Sum Sq Mean Sq F value Pr(>F)
## group 4 200 50.1 1.63 0.183
## group: c1 1 152 151.8 4.94 0.031 *
## Residuals 45 1382 30.7
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
The F and p values for this contrast are exactly the same as before, as they should be, and the critical Scheffe F also remains unchanged. Not surprisingly, the results of our Scheffe test are the same: the contrast is not significant. This result makes sense because the Scheffe adjustment does not depend on the number of contrasts that we perform. Instead, we assume that our inspection of the data allowed us to do many contrasts implicitly, and we selected the one that we thought had a chance of being significant.
Now let’s try it with the emmeans
commands:
library(emmeans)
aov.em <- emmeans(aov.03,specs="group")
contrast(aov.em,method=list(c1),adjust="scheffe")
## contrast estimate SE df t.ratio p.value
## c(-0.25, -0.25, -0.25, -0.25, 1) 4.36 1.96 45 2.223 0.0313
##
## P value adjustment: scheffe method with rank 1
Surprise! The contrast is significant using the Scheffe
adjustment. What happened? Notice the last line in the output: the p
values have been adjusted with the
"scheffe method with rank 1"
, not rank 4 as before. It
seems that the Scheffe adjustment used by contrast
is
adjusting for multiple comparisons, rather than performing a traditional
Scheffe test. In the previous case we had four p values and here we have
only one. Hence, in this case, the p value has not been adjusted at all.
This point can be illustrated by comparing the output to the results
obtained with no adjustment:
contrast(aov.em,method=list(c1),adjust="none")
## contrast estimate SE df t.ratio p.value
## c(-0.25, -0.25, -0.25, -0.25, 1) 4.36 1.96 45 2.223 0.0313
The p value is the same as the one obtained with the
scheffe
adjustment. Clearly, this is not what we want to
happen because the Scheffe test should control Type I error in the case
where we looked at the data and implicitly performed many
contrasts. This point was discussed by the author of the
emmeans
package here.
Fortunately, there is a simple way of addressing this issue. In the
following code, I save the results of the contrast in the variable
con
and list the results with the summary
command which includes the parameter scheffe.rank
. By
setting scheffe.rank
to 4, which corresponds to the degrees
of freedom of group
, I am telling emmeans
to
provide the full Scheffe adjustment.
con <- contrast(aov.em,method=list(c1),adjust="scheffe")
summary(con,adjust="scheffe",scheffe.rank=4) # set rank to df for group!
Note that the p value is the same as the one obtained when we
performed the Scheffe test with four orthogonal contrasts. So this is
the correct way to perform the post-hoc Scheffe adjustment.
Unfortunately, the scheffe.rank
parameter works in the
summary
command but not in the contrast
command, at least with emmeans
version 1.8.8.
In conclusion, the correct way to the Scheffe test with
emmeans
is to set scheffe.rank
to equal the
degrees of freedom of the grouping variable, even if you perform only
one post-hoc contrast.