Sunteți pe pagina 1din 29

ANOVA contrasta en R

Joan Riera
3 de diciembre de 2017

 Establecer tus propios contrastes


o El camino rapido y sucio
o La forma correcta: un protocolo simple
 La larga explicación teórica.
o Contrastes de tratamiento
o Otros contrastes estándar

El propósito de este documento es ayudarlo a comprender y definir los contrastes


planificados en R. Las dos primeras secciones son muy pragmáticas y brindan
información muy breve sobre cómo crear sus contrastes. La última sección ofrece
una explicación más completa de cómo y por qué todo esto se hace de la manera en
que se hace.
Como datos de ejemplo, usaremos PlantGrowth, con un solo factor ( group) con
tres niveles:

data("PlantGrowth")
boxplot(weight ~group, data = PlantGrowth)
Ajustemos un modelo usando aovcomo referencia.

mod0 <- aov(weight ~ group, data = PlantGrowth)


summary(mod0)
Df Sum Sq Mean Sq F value Pr(>F)
group 2 3.766 1.8832 4.846 0.0159 *
Residuals 27 10.492 0.3886
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

R utiliza por defecto los llamados contrastes de tratamiento , donde cada nivel del
factor se compara con el primer nivel o el nivel de referencia (el nivel de control, en
nuestro caso). 1 Puede ver estos contrastes usando summary.lm:

summary.lm(mod0)

Call:
aov(formula = weight ~ group, data = PlantGrowth)
Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0320 0.1971 25.527 <2e-16 ***
grouptrt1 -0.3710 0.2788 -1.331 0.1944
grouptrt2 0.4940 0.2788 1.772 0.0877 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.6234 on 27 degrees of freedom


Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591

Observe cómo la intersección es la media esperada para el tratamiento de control,


mientras que los otros dos coeficientes dan la diferencia en las medias esperadas
de trt1y trt2con respecto a ctrl. Puede verificar esto fácilmente:

# means per group:


(means <- with(PlantGrowth, tapply(weight, group, mean)))
ctrl trt1 trt2
5.032 4.661 5.526

y las diferencias con respecto al control:

c(means[1], means[2:3] - means[1])


ctrl trt1 trt2
5.032 -0.371 0.494

Estos contrastes son buenos si está interesado en comparar con un nivel base (por
ejemplo, un control), pero tenga en cuenta que puede que no sean adecuados para
diseños más complejos, especialmente si tiene datos desequilibrados y desea
utilizar sumas de cuadrados Tipo 3 .
Establecer tus propios contrastes
El camino rapido y sucio
Supongamos que está interesado en dos contrastes:
 control versus tratamientos
 tratamiento 1 versus tratamiento 2
En primer lugar, tenga en cuenta que solo puede especificar una cantidad de
contrastes igual a la cantidad de niveles de su factor menos uno (es decir, 2
contrastes en este caso).
Puede especificar sus contrastes definiendo una matriz (llamémosla BsBs), como
sigue:
# each vector becomes a column in the resulting matrix:
Bs <- cbind(c(1, -1/2, -1/2),
c(0, 1, -1))
Bs
[,1] [,2]
[1,] 1.0 0
[2,] -0.5 1
[3,] -0.5 -1

Voy a agregar nombres de columna y fila solo para que sea más legible. Los
nombres no son obligatorios, pero son útiles (especialmente los nombres de
columna):

rownames(Bs) <- levels(PlantGrowth$group)


colnames(Bs) <- c("ctrl vs trt", "trt1 vs trt2")
Bs
ctrl vs trt trt1 vs trt2
ctrl 1.0 0
trt1 -0.5 1
trt2 -0.5 -1

Tenga en cuenta que las sumas de columnas son iguales a 0.


La matriz se puede leer de la siguiente manera.
 la primera columna representa el primer contraste: control versus la media
de ambos tratamientos. Usted especifica esto dando igual peso a ambos
lados del contraste, pero con signo opuesto: 1 para el control y -1 (es decir, (-
0.5) + (-0.5)) para los tratamientos.
 la segunda columna representa el segundo contraste: tratamiento 1 versus
tratamiento 2. Nuevamente, usted especifica esto dando igual peso a ambos
lados del contraste, pero con signo opuesto: 1 a trt1y -1
a trt2. Aquí, ctrlno juega ningún papel, por lo que damos es un cero.
Ahora está listo para ajustar nuevamente el modelo, pero con diferentes contrastes:

mod1 <- aov(weight ~ group, data = PlantGrowth,


contrasts = list(group = Bs))
summary(mod1)
Df Sum Sq Mean Sq F value Pr(>F)
group 2 3.766 1.8832 4.846 0.0159 *
Residuals 27 10.492 0.3886
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Tenga en cuenta que la tabla de análisis de varianza no se ve afectada por la


elección de contrastes, pero las estimaciones de los parámetros han cambiado:

summary.lm(mod1)

Call:
aov(formula = weight ~ group, data = PlantGrowth, contrasts = list(group
= Bs))

Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0730 0.1138 44.573 < 2e-16 ***
groupctrl vs trt -0.0410 0.1610 -0.255 0.80086
grouptrt1 vs trt2 -0.4325 0.1394 -3.103 0.00446 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.6234 on 27 degrees of freedom


Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591

Observe cómo agregar nombres de columna a la matriz BBAyuda a leer la tabla de


arriba. Ahora, la intersección es la gran media (la media de las medias):
mean(means)
[1] 5.073

El primer parámetro nos ayuda a probar el primer contraste. La hipótesis nula para
el ttLa prueba es, como de costumbre, que el parámetro no es diferente de cero, es
decir, que la respuesta media para los tratamientos no es diferente del control (¡lo
que no implica que ambos tratamientos no sean diferentes del control!). En este
caso, aceptamos la hipótesis nula.
El segundo parámetro compara el tratamiento 1 y el tratamiento 2. El valor p está
muy por debajo del nivel de significancia de 0.05, por lo que rechazamos la
hipótesis nula.
Es muy importante que comprenda que esta forma de definir los
contrastes solo es válida si sus contrastes son independientes , es decir, no
está haciendo implícitamente la misma comparación en dos contrastes diferentes.
Puede verificar que sus contrastes sean independientes (es decir, ortogonales)
entre ellos y contra la intercepción ejecutando el siguiente código:

B <- cbind(1, Bs) # add intercept


crossprod(B) # t(B) x B; t(B) is the transposed of B
ctrl vs trt trt1 vs trt2
3 0.0 0
ctrl vs trt 0 1.5 0
trt1 vs trt2 0 0.0 2

Si el resultado es una matriz diagonal (solo cero en la diagonal principal), está bien.
Supongamos por un momento que está interesado en los siguientes dos contrastes:

 control vs tratamientos
 control vs tratamiento 2
Observe cómo, implícitamente, el segundo contraste es parte del primer contraste:
no son independientes.
Usando el cheque anterior:

Bs <- cbind(c(1, -1/2, -1/2),


c(1, 0, -1))
B <- cbind(1, Bs)
crossprod(B)
[,1] [,2] [,3]
[1,] 3 0.0 0.0
[2,] 0 1.5 1.5
[3,] 0 1.5 2.0

Que obviamente no es una matriz diagonal. En este caso, no está definiendo los
contrastes que piensa: necesitaría usar el protocolo (ligeramente) más complicado
que se explica a continuación.

La forma correcta: un protocolo simple


Para definir cualquier tipo de contrastes planificados, se necesita un procedimiento
un poco más complicado. Si realmente quieres entender el significado de lo que
muestro aquí, lee la sección sobre teoría.
Primero definamos el contraste ortogonal que definimos anteriormente, y luego,
siguiendo el mismo procedimiento, definiremos el segundo contraste no ortogonal
que no pudimos definir anteriormente.
Ejemplo 1: un contraste ortogonal
Recordemos cuáles son los contrastes:
 control versus tratamientos
 tratamiento 1 versus tratamiento 2
Podemos definir los mismos contrastes de la siguiente manera:

1. definir contrastes son filas de una matriz de contraste, C :

C <- rbind(c(1, -1/2, -1/2), # note rbind, not cbind


c(0, 1, -1))
rownames(C) <- c("ctrl vs trt", "trt1 vs trt2")
C
[,1] [,2] [,3]
ctrl vs trt 1 -0.5 -0.5
trt1 vs trt2 0 1.0 -1.0

2. Agregue una primera fila de 1 dividida por el número de niveles:

C <- rbind(Ave = rep(1/3, 3), C)


C
[,1] [,2] [,3]
Ave 0.3333333 0.3333333 0.3333333
ctrl vs trt 1.0000000 -0.5000000 -0.5000000
trt1 vs trt2 0.0000000 1.0000000 -1.0000000

3. Tome el inverso de la matriz:

B <- solve(C)
B
Ave ctrl vs trt trt1 vs trt2
[1,] 1 0.6666667 0.0
[2,] 1 -0.3333333 0.5
[3,] 1 -0.3333333 -0.5

4. elimine la primera columna y use la matriz resultante para definir los


contrastes en su ANOVA:

Bs <- B[, -1]


mod1b <- aov(weight ~ group, data = PlantGrowth,
contrasts = list(group = Bs))
summary.lm(mod1b)

Call:
aov(formula = weight ~ group, data = PlantGrowth, contrasts = list(group
= Bs))

Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0730 0.1138 44.573 < 2e-16 ***
groupctrl vs trt -0.0615 0.2414 -0.255 0.80086
grouptrt1 vs trt2 -0.8650 0.2788 -3.103 0.00446 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.6234 on 27 degrees of freedom


Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591

Tenga en cuenta que cuando lo haces de esta manera, los valores de los parámetros
estimados son fáciles de interpretar: se definen por su matriz de contraste C . Usaré
el paquete fractionalpara mostrar números fraccionarios:

library(fractional)
fractional(C)
[,1] [,2] [,3]
Ave 1/3 1/3 1/3
ctrl vs trt 1 -1/2 -1/2
trt1 vs trt2 . 1 -1

que es solo:

print(C)
[,1] [,2] [,3]
Ave 0.3333333 0.3333333 0.3333333
ctrl vs trt 1.0000000 -0.5000000 -0.5000000
trt1 vs trt2 0.0000000 1.0000000 -1.0000000

pero con puntos en lugar de ceros y fracciones en lugar de números decimales.


Recuperemos los coeficientes del modelo:
coef(mod1b)
(Intercept) groupctrl vs trt grouptrt1 vs trt2
5.0730 -0.0615 -0.8650

y el grupo significa:

with(PlantGrowth, tapply(weight, group, mean))


ctrl trt1 trt2
5.032 4.661 5.526

Como verá a continuación, la matriz de contrastes multiplicada por el grupo


significa dar los valores de los parámetros. Por lo tanto, la primera línea
proporciona el primer parámetro, que es solo el promedio de las medias de grupo
(la gran media):

mean(PlantGrowth$weight)
[1] 5.073

La segunda línea (el primer contraste) es la media de control menos la media de los
dos tratamientos:

5.032 - mean(c(4.661, 5.526))


[1] -0.0615

La tercera línea es la diferencia entre las medias para los tratamientos 1 y 2:

4.661 - 5.526
[1] -0.865

Por otro lado, la matriz B nos da las medias esperadas del grupo cuando se
multiplica por el vector de coeficientes. En nuestro caso, B es:

fractional(B)
Ave ctrl vs trt trt1 vs trt2
[1,] 1 2/3 .
[2,] 1 -1/3 1/2
[3,] 1 -1/3 -1/2

Entonces, por ejemplo, la media esperada para el tratamiento 1 es


1b1−13b2+12b31b1−13b2+12b3
es decir

b <- coef(mod1b)
b[1] - 1/3*b[2] + 1/2*b[3]
(Intercept)
4.661

Ejemplo 2: el contraste no ortogonal


Ahora codifiquemos la segunda comparación planificada, que no era ortogonal y no
pudimos definir correctamente utilizando el primer método rápido y sucio:

 control vs tratamientos
 control vs tratamiento 2

Usando el mismo protocolo que acabamos de describir:

# define C
C <- rbind(c(1, -1/2, -1/2), # note rbind, not cbind
c(1, 0, -1))
rownames(C) <- c("ctrl vs trt", "ctrl vs trt2")

# add grand mean first line:


C <- rbind(Ave = rep(1/3, 3), C)

# take inverse and remove first column:


B <- solve(C)
Bs <- B[, -1]

# this is the matrix we'll use to define contrasts in `aov`:


fractional(Bs)
ctrl vs trt ctrl vs trt2
[1,] 2/3 .
[2,] -4/3 1
[3,] 2/3 -1
Y el ANOVA con los contrastes deseados:

mod1c <- aov(weight ~ group, data = PlantGrowth,


contrasts = list(group = Bs))
summary.lm(mod1c)

Call:
aov(formula = weight ~ group, data = PlantGrowth, contrasts = list(group
= Bs))

Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0730 0.1138 44.573 <2e-16 ***
groupctrl vs trt -0.0615 0.2414 -0.255 0.8009
groupctrl vs trt2 -0.4940 0.2788 -1.772 0.0877 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.6234 on 27 degrees of freedom


Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591

Observe cómo, tal como especificamos en la matriz de contrastes C , el valor para el


segundo parámetro (el primer contraste, control versus tratamientos) es la media
del control menos la media de los dos tratamientos, al igual que en el ejemplo
anterior, mientras que El tercer parámetro es la media del control menos la media
del segundo tratamiento:

5.032 - 5.526
[1] -0.494

La larga explicación teórica.


Aquí usaré nuevamente los datos de PlantGrowth, pero para mantener la
producción corta, tomaré solo tres observaciones por grupo:

set.seed(5)
pg <- PlantGrowth[c(sample(1:10, 3), sample(11:20, 3), sample(21:30, 3)),
]
pg
weight group
3 5.18 ctrl
7 5.17 ctrl
8 4.53 ctrl
13 4.41 trt1
11 4.81 trt1
16 3.83 trt1
26 5.29 trt2
28 6.15 trt2
29 5.80 trt2

Comencemos por lo básico, que es cómo codificar numéricamente una variable


categórica. Una forma simple e intuitiva sería utilizar variables ficticias, una para
cada nivel, de modo que un ficticio para el nivel 1 tome un valor de 1 si la
observación pertenece a ese grupo y 0 en caso contrario.
Podemos obligar a R a hacer eso eliminando la intersección al ajustar el
modelo. Pronto verá que esto es inútil:

mod0 <- aov(weight ~ 0 + group, data = pg)

Bajo este modelo lineal, el valor esperado para una observación dada viene dado
por la siguiente expresión:
y^= X my^=Xm
donde XXes la matriz modelo , una n×pnorte×pagsmatriz ( nnorteobservaciones
veces ppagsgrupos) y μmes la p×1pags×1grupo significa vector. En R, podemos
recuperar la matriz modelo con:
(X <- model.matrix(mod0))
groupctrl grouptrt1 grouptrt2
3 1 0 0
7 1 0 0
8 1 0 0
13 0 1 0
11 0 1 0
16 0 1 0
26 0 0 1
28 0 0 1
29 0 0 1
attr(,"assign")
[1] 1 1 1
attr(,"contrasts")
attr(,"contrasts")$group
[1] "contr.treatment"

donde puede ver que nuestra variable categórica weightestá, en efecto,


simplemente codificada como tres variables ficticias. 2 Esto es fácil de entender,
pero resulta inútil, porque si observa los parámetros del modelo y las pruebas t
individuales:

summary.lm(mod0)

Call:
aov(formula = weight ~ 0 + group, data = pg)

Residuals:
Min 1Q Median 3Q Max
-0.52 -0.43 0.06 0.22 0.46

Coefficients:
Estimate Std. Error t value Pr(>|t|)
groupctrl 4.9600 0.2513 19.73 1.10e-06 ***
grouptrt1 4.3500 0.2513 17.31 2.38e-06 ***
grouptrt2 5.7467 0.2513 22.86 4.58e-07 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.4353 on 6 degrees of freedom
Multiple R-squared: 0.9951, Adjusted R-squared: 0.9926
F-statistic: 403.9 on 3 and 6 DF, p-value: 2.612e-07

verá que las pruebas t son triviales, porque todo lo que estamos probando es si la
media de cada grupo es diferente de 0 o no:

with(pg, tapply(weight, group, mean))


ctrl trt1 trt2
4.960000 4.350000 5.746667

Por lo tanto, no estamos haciendo ningún contraste entre los niveles del factor y,
por lo tanto, no estamos probando de ninguna manera si hay diferencias en las
medias entre los niveles.
Para obtener resultados más significativos, necesitamos codificar nuestras
variables de manera diferente, y ahí es donde entran los contrastes .
En R, los contrastes predeterminados se denominan contrastes de tratamiento ,
por lo que primero desarrollaremos la teoría para ellos, luego los ampliaremos a
otros contrastes estándar, ya predefinidos en R, y luego a cualquier conjunto
planificado de contrastes.

Contrastes de tratamiento
Supongamos ahora que queremos codificar nuestra variable categórica para
obtener tratamientos más significativos. Esto es equivalente a usar un conjunto
alternativo de parámetros definidos como:
b= C μb=Cm
donde CCes una p×ppags×pagsmatriz. Si CC es no singular y por lo tanto
invertible, podemos escribir:
μ = C−1b= B βm=C−1b=Bb
y podemos escribir nuestro modelo:
y^= X µ = X B by^=Xm=XBb
Se puede mostrar 3 que, si elegimos una transformación en CCtal que la primera
columna de la matriz BBes una columna de unos, esto se convierte en una
intersección (es decir, β0b0) y los parámetros restantes
( β1, ... , bp - 1b1,…,bpags−1), si se elige bien, produce contrastes significativos y, lo
que es más importante, la hipótesis nula (que todas las medias de grupo son
iguales) es verdadera si y solo si todos los βbpor encima de β0b0(es
decir, b1, ... , bp - 1b1,…,bpags−1) son iguales a cero.
Los contrastes de tratamiento se definen de tal manera que la intersección es la
media para el primer grupo de referencia, y cada uno de los coeficientes restantes
son diferencias entre cada nivel por encima del primer y el primer nivel.
Si ajustamos un modelo con los contrastes de tratamiento predeterminados:

mod.treat <- aov(weight ~ group, pg)


summary.lm(mod.treat)

Call:
aov(formula = weight ~ group, data = pg)

Residuals:
Min 1Q Median 3Q Max
-0.52 -0.43 0.06 0.22 0.46

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.9600 0.2513 19.734 1.1e-06 ***
grouptrt1 -0.6100 0.3554 -1.716 0.1369
grouptrt2 0.7867 0.3554 2.213 0.0688 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.4353 on 6 degrees of freedom


Multiple R-squared: 0.7212, Adjusted R-squared: 0.6283
F-statistic: 7.761 on 2 and 6 DF, p-value: 0.02167

Analicemos ahora qué ha hecho R en términos de BBy CC matrices.


Para el tratamiento contrasta con tres niveles, el BB matriz puede obtenerse así:
(Bs <- contr.treatment(3))
2 3
1 0 0
2 1 0
3 0 1

donde Bsestá la llamada matriz de codificación . El bB matriz es la matriz de


codificación con una columna de unidades (la intersección) antepuesta:
B=[1pags,B∗]B=[1pags,B∗]
En R:

(B <- cbind(1, Bs))


2 3
1 1 0 0
2 1 1 0
3 1 0 1

Recuerde desde arriba que μ=Bβm=Bb, entonces esta matriz nos dice qué
coeficientes necesitamos sumar (y multiplicado por qué valores, en este caso todos)
para obtener la media grupal. Por lo tanto, la media para el primer grupo es
solo β0b0, mientras que la media para el segundo grupo es β0+ b1b0+b1, y la media
para el tercer grupo es β0+ b2b0+b2. (¡Usted puede comprobarlo!)
En este caso, la matriz de codificación no se puede leer directamente para obtener
los contrastes (es decir, lo que probamos en cada línea de t.prueba anterior). Esto
se lee mejor en la matriz de contraste , CC, que se obtiene de la inversa de BB:
(C <- solve(B))
1 2 3
1 0 0
2 -1 1 0
3 -1 0 1

Esta es la matriz que nos ayuda a comprender cada una de las líneas de la salida
anterior (desde sumamry.lm).
Recuerda que β= C μb=Cmy, por lo tanto, la matriz de contraste multiplicada por
las medias del grupo nos da los valores de los coeficientes del modelo. Como
expresiones matemáticas:
b0= m1b0=m1
b1= m2- m1b1=m2−m1
y
b2= m3- m1b2=m3−m1
Para cada una de las pruebas t en la salida, la hipótesis nula es que el coeficiente es
cero. Por lo tanto, bajo la hipótesis nula:
m1=0m1=0
0 = m2- m1⇒μ1= m20=m2−m1⇒m1=m2
0 = m3- m1⇒μ1= m30=m3−m1⇒m1=m3
Finalmente, si recordamos que
y^= X µ = X B by^=Xm=XBb
ahora la matriz modelo es XBXB. Veamos qué obtuvimos para nuestro modelo:
model.matrix(mod.treat)
(Intercept) grouptrt1 grouptrt2
3 1 0 0
7 1 0 0
8 1 0 0
13 1 1 0
11 1 1 0
16 1 1 0
26 1 0 1
28 1 0 1
29 1 0 1
attr(,"assign")
[1] 0 1 1
attr(,"contrasts")
attr(,"contrasts")$group
[1] "contr.treatment"

que es exactamente:

X %*% B
2 3
3 1 0 0
7 1 0 0
8 1 0 0
13 1 1 0
11 1 1 0
16 1 1 0
26 1 0 1
28 1 0 1
29 1 0 1

En resumen, al definir adecuadamente una matriz de contraste y la matriz de


codificación correspondiente, terminamos codificando nuestro factor y
parametrizando nuestro modelo de tal manera que garanticemos que:
 tenemos una intersección, que en este caso es la media del primer grupo
pero con mayor frecuencia, como veremos, es la gran media
 tenemos un conjunto de p-1pags−1parámetros, correspondientes p-
1pags−1 contrastes, que son significativos.

Otros contrastes estándar


Como ya se mencionó, R usa contrastes de tratamiento por defecto. Estos son útiles
en un contexto de regresión y fáciles de entender en un contexto ANOVA, pero
sufren algunos problemas. Una es que los contrastes no son ortogonales, lo cual
puede verificar haciendo el producto cruzado de B:

crossprod(B)
2 3
3 1 1
2 1 1 0
3 1 0 1

que no es una matriz diagonal. (Recuerde que dos vectores son ortogonales si su
producto es cero).
Debido a que no son ortogonales, los contrastes de tratamiento no se pueden usar
con sumas de cuadrados Tipo III, lo que puede ser útil cuando el diseño no está
equilibrado. Por estas razones, otro software estadístico utiliza otros contrastes
para las variables categóricas por defecto.
Algunos de estos se pueden definir en R utilizando funciones de conveniencia
(hacer help(contr. treatment)una lista).

Helmert contrastes
Para un factor con tres niveles, la matriz de codificación B∗B∗ para contrastes de
Helmert es:
(Bs <- contr.helmert(3))
[,1] [,2]
1 -1 -1
2 1 -1
3 0 2

Estos son contrastes ortogonales; si hacemos el producto cruzado de BB:


B <- cbind(1, Bs)
crossprod(B)
[,1] [,2] [,3]
[1,] 3 0 0
[2,] 0 2 0
[3,] 0 0 6

Es diagonal.
En los contrastes de Helmert, β0b0(la intersección) es la gran media, y los
contrastes comparan la media de cada grupo con la media de los niveles anteriores
(es decir, el grupo 2 frente al grupo 1, el grupo 3 frente a la media de los grupos 1 y
2, y así sucesivamente si hay más niveles) Esto se puede ver en la matriz de
codificación anterior (porque los contrastes son ortogonales), y más claramente en
la matriz de contraste:
(C <- solve(B))
1 2 3
[1,] 0.3333333 0.3333333 0.3333333
[2,] -0.5000000 0.5000000 0.0000000
[3,] -0.1666667 -0.1666667 0.3333333

Como fracciones:

fractional(C)
1 2 3
[1,] 1/3 1/3 1/3
[2,] -1/2 1/2 .
[3,] -1/6 -1/6 1/3

donde la primera línea corresponde a la intersección (gran media), la segunda línea


es el primer contraste:
b1=−12m1+12m2=0⇒μ1= m2b1=−12m1+12m2=0⇒m1=m2
y el segundo contraste (tercera línea) es:
b1=−16m1−16m2+13m3=0⇒μ3=12( m1+ m2)b1=−16m1−16m2+13m3=0⇒m3=12(
m1+m2)
En nuestro ejemplo, podemos ajustar el modelo con el contraste especificado de la
siguiente manera:

mod.helm <- aov(weight ~ group, data = pg,


contrasts = list(group = contr.helmert))
summary.lm(mod.helm)

Call:
aov(formula = weight ~ group, data = pg, contrasts = list(group = contr.h
elmert))

Residuals:
Min 1Q Median 3Q Max
-0.52 -0.43 0.06 0.22 0.46

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0189 0.1451 34.587 3.89e-08 ***
group1 -0.3050 0.1777 -1.716 0.1369
group2 0.3639 0.1026 3.546 0.0121 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.4353 on 6 degrees of freedom


Multiple R-squared: 0.7212, Adjusted R-squared: 0.6283
F-statistic: 7.761 on 2 and 6 DF, p-value: 0.02167

Tenga en cuenta que, obviamente, la matriz modelo reproduce la matriz de


codificación:

model.matrix(mod.helm)
(Intercept) group1 group2
3 1 -1 -1
7 1 -1 -1
8 1 -1 -1
13 1 1 -1
11 1 1 -1
16 1 1 -1
26 1 0 2
28 1 0 2
29 1 0 2
attr(,"assign")
[1] 0 1 1
attr(,"contrasts")
attr(,"contrasts")$group
[,1] [,2]
ctrl -1 -1
trt1 1 -1
trt2 0 2

Suma contrastes
Los contrastes de suma son otra especificación de contrastes que encontrará en la
mayoría de los programas estadísticos.
Para un factor con tres niveles, la matriz de codificación, B∗B∗, es:
(Bs <- contr.sum(3))
[,1] [,2]
1 1 0
2 0 1
3 -1 -1

Y podemos adaptar el modelo al igual que arriba:

mod.sum <- aov(weight ~ group, data = pg,


contrasts = list(group = contr.sum))
summary.lm(mod.sum)

Call:
aov(formula = weight ~ group, data = pg, contrasts = list(group = contr.s
um))

Residuals:
Min 1Q Median 3Q Max
-0.52 -0.43 0.06 0.22 0.46

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.01889 0.14511 34.587 3.89e-08 ***
group1 -0.05889 0.20522 -0.287 0.7838
group2 -0.66889 0.20522 -3.259 0.0173 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.4353 on 6 degrees of freedom


Multiple R-squared: 0.7212, Adjusted R-squared: 0.6283
F-statistic: 7.761 on 2 and 6 DF, p-value: 0.02167

Y, por supuesto, la matriz de codificación nos dice cómo se parametriza el factor en


la matriz del modelo:

model.matrix(mod.sum)
(Intercept) group1 group2
3 1 1 0
7 1 1 0
8 1 1 0
13 1 0 1
11 1 0 1
16 1 0 1
26 1 -1 -1
28 1 -1 -1
29 1 -1 -1
attr(,"assign")
[1] 0 1 1
attr(,"contrasts")
attr(,"contrasts")$group
[,1] [,2]
ctrl 1 0
trt1 0 1
trt2 -1 -1

Y nos dice cómo los medios grupales están relacionados con los parámetros del
modelo:
m1= b0+ b1m1=b0+b1
m2= b0+ b2m2=b0+b2
m3= b0- b1- b2m3=b0−b1−b2
Pero realmente no podemos ver lo que se compara hasta que realmente
construimos la matriz de contraste:
C <- solve(cbind(1, Bs))
fractional(C)
1 2 3
[1,] 1/3 1/3 1/3
[2,] 2/3 -1/3 -1/3
[3,] -1/3 2/3 -1/3

Entonces, la primera línea, como de costumbre, especifica la gran media, y bajo la


hipótesis nula de que los parámetros son cero, los contrastes (líneas 2 y 3) son
(recordando que β= C μb=Cm):
m1=12( m2+ m3)m1=12(m2+m3)
o equivalente:
m1=13( m1+ m2+ m3)⇒μ1= m¯m1=13(m1+m2+m3)⇒m1=m¯
y
m2=12( m1+ m3)m2=12(m1+m3)
o equivalente,
m2= m¯m2=m¯
Por lo tanto, cada grupo se compara con la gran media (pero recuerde que debido a
que hay una intercepción, estamos limitados a p-1pags−1contrastes, en este caso
dos, entonces el contraste para μ3m3 no se realiza)
En otras palabras, estamos probando desviaciones de la media, por lo que estos
contrastes también se conocen como contrastes de desviación .
Puede ver esto más claramente para un factor con 5 niveles, por ejemplo:

Bs <- contr.sum(5)
B <- cbind(1, Bs)
fractional(solve(B))
1 2 3 4 5
[1,] 1/5 1/5 1/5 1/5 1/5
[2,] 4/5 -1/5 -1/5 -1/5 -1/5
[3,] -1/5 4/5 -1/5 -1/5 -1/5
[4,] -1/5 -1/5 4/5 -1/5 -1/5
[5,] -1/5 -1/5 -1/5 4/5 -1/5

Tenga en cuenta que los contrastes de suma no son ortogonales:

crossprod(B)
[,1] [,2] [,3] [,4] [,5]
[1,] 5 0 0 0 0
[2,] 0 2 1 1 1
[3,] 0 1 2 1 1
[4,] 0 1 1 2 1
[5,] 0 1 1 1 2

que no es una matriz diagonal.


Tenga en cuenta también que la BB matriz:
fractional(B)
[,1] [,2] [,3] [,4] [,5]
1 1 1 . . .
2 1 . 1 . .
3 1 . . 1 .
4 1 . . . 1
5 1 -1 -1 -1 -1

puede leerse como medio (recuerde que μ=Bβm=Bb) ese:


myo= b0+ byo,i = 1 , ... , 4myo=b0+byo,yo=1,…,4
mientras que la quinta línea nos dice que:
m5= b0−∑i = 14byo= b0+ b5m5=b0−∑yo=14byo=b0+b5
lo que implica:
∑i = 1pagsbyo=0∑yo=1pagsbyo=0
Por lo tanto, el nombre suma contrastes, ya que se introduce la restricción de que
los efectos suman cero.
Contrastes definidos por el usuario
En vista de que acabamos de revisar, ahora es fácil entender el protocolo que
establecimos en la segunda sección anterior:
1. construir una matriz de contraste, CC, donde la primera línea es la gran
media (un vector promedio) y las líneas restantes son contrastes
(combinaciones lineales de grupos significan que los coeficientes suman
cero),
2. obtener la matriz BBcomo el inverso de CC: B=C−1B=C−1
3. eliminar la primera columna (las de la intersección) para obtener la matriz
de codificación B∗B∗
4. use la matriz de codificación para especificar los contrastes en la llamada
a aov.
Repasemos el procedimiento en R usando los contrastes de ejemplo usados
anteriormente:

# 1. build contrasts as lines:


C <- rbind(c(1, -1/2, -1/2),
c(0, 1, -1))
rownames(C) <- c("ctrl vs trt", "trt1 vs trt2")

# Add averaging vector to build C:


C <- rbind(Ave = rep(1/3, 3), C)

# take the inverse to obtain B:


B <- solve(C)
# remove first column to get the coding matrix, Bs (B star):
Bs <- B[, -1]

# use the coding matrix within aov:


mod <- aov(weight ~ group, data = PlantGrowth,
contrasts = list(group = Bs))
summary.lm(mod)

Call:
aov(formula = weight ~ group, data = PlantGrowth, contrasts = list(group
= Bs))

Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0730 0.1138 44.573 < 2e-16 ***
groupctrl vs trt -0.0615 0.2414 -0.255 0.80086
grouptrt1 vs trt2 -0.8650 0.2788 -3.103 0.00446 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.6234 on 27 degrees of freedom


Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591

Tenga en cuenta que la parte confusa sobre cómo R trata los contrastes es que el
argumento contrasts =en aovrealidad no es pedir una matriz de contrastes, ¡sino
una matriz de codificación!
Finalmente, si va a ajustar varios modelos a un factor (o factores), puede definir los
contrastes para el factor en sí y luego usarlos aovdirectamente. Por ejemplo:

contrasts(PlantGrowth$group) <- Bs
mod <- aov(weight ~ group, data = PlantGrowth)
summary.lm(mod)

Call:
aov(formula = weight ~ group, data = PlantGrowth)

Residuals:
Min 1Q Median 3Q Max
-1.0710 -0.4180 -0.0060 0.2627 1.3690

Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.0730 0.1138 44.573 < 2e-16 ***
groupctrl vs trt -0.0615 0.2414 -0.255 0.80086
grouptrt1 vs trt2 -0.8650 0.2788 -3.103 0.00446 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.6234 on 27 degrees of freedom


Multiple R-squared: 0.2641, Adjusted R-squared: 0.2096
F-statistic: 4.846 on 2 and 27 DF, p-value: 0.01591

Si necesita restaurar los contrastes a los factores de tratamiento predeterminados,


simplemente haga lo siguiente:

contrasts(PlantGrowth$group) <- contr.treatment

1. Utilícelo levelspara averiguar el orden de los niveles en un


factor, factoro relevelpara cambiarlo. ↩
2. puedes ignorar los atributos aquí de forma segura. ↩
3. Se puede encontrar una excelente explicación, en la que se basan estas
notas, en la viñeta del paquete codingMatrices: Venables, B. (2017) Matrices
de codificación, matrices de contraste y modelos lineales. https://cran.r-
project.org/web/packages/codingMatrices/index.htm