---
title: "Variance explained for contrasts"
description: |
Learning note of using contrast matrix for sum of squares
author: Mark Lai
date: "2024-04-12"
categories:
- Statistics
---
## One-Way ANOVA
Consider 4 groups, each with 10 observations, and the group means are 5, 7, 9, and 11.
```{r}
set.seed(2201)
num_obs <- 10
err <- rnorm(num_obs)
err <- (err - mean(err))
mu <- c(11, 7, 5, 9)
y <- rep(mu, each = num_obs) + err
group <- rep(LETTERS[1:4], each = num_obs)
aov(y ~ group)
```
Using `lm`
```{r}
lm1 <- lm(y ~ group)
anova(lm1)
```
Using contrast matrix
```{r}
fac <- factor(group)
contrasts(fac) <- contr.sum(4) # effect coding
lm2 <- lm(y ~ fac)
anova(lm2)
```
Notice that we get the same sum of squares (SS). Next, we'll compute SS by hand.
Let $\mu_j$ be the population mean for group $j$, and $\bar Y_{.j}$ be the sample group mean. Let $\mathbf{L}$ be a matrix such that each column is a contrast vector. For example,
```{r}
contr.sum(4)
```
Note that each column sums to zero. Then, for a balanced design, the SS accounted for by $\mathbf{L}$ is (e.g., [Rencher & Schaalje, 2008](https://onlinelibrary.wiley.com/doi/book/10.1002/9780470192610))
$$
n [\mathbf{L}^\intercal \bar{\mathbf{Y}}]^\intercal [\mathbf{L}^\intercal \mathbf{L}]^{-1} [\mathbf{L}^\intercal \bar{\mathbf{Y}}],
$$
```{r}
L_mat <- contr.sum(length(mu))
Lmu <- crossprod(L_mat, mu)
num_obs * crossprod(Lmu, solve(crossprod(L_mat), Lmu))
```
## Interaction
```{r}
n2 <- num_obs / 2
err <- rnorm(n2)
err <- (err - mean(err))
mu2 <- c(5, 7, 9, 11, 6, 12, 8, 10)
group2 <- rep(rep(1:2, each = n2), length(mu))
y2 <- rep(mu2, each = n2) + err
aov(y2 ~ group * group2)
```
Using contrast coding
```{r}
fac <- factor(group)
contrasts(fac) <- contr.sum(4)
fac2 <- factor(group2)
contrasts(fac2) <- contr.sum(2)
model.matrix(~ fac * fac2) |> head()
lm(y2 ~ fac * fac2) |> anova()
```
Using contrast matrix
```{r}
# Extract the contrast matrix
df2 <- unique(data.frame(fac, fac2))
(X <- model.matrix(~ fac * fac2, data = df2))
# For main effect of group
L_mat <- X[, 2:4]
Lmu <- crossprod(L_mat, mu2)
n2 * crossprod(Lmu, solve(crossprod(L_mat), Lmu))
# For main effect of group2
L_mat2 <- X[, 5, drop = FALSE]
Lmu2 <- crossprod(L_mat2, mu2)
n2 * crossprod(Lmu2, solve(crossprod(L_mat2), Lmu2))
# For interaction
L_mat3 <- X[, 6:8]
Lmu3 <- crossprod(L_mat3, mu2)
n2 * crossprod(Lmu3, solve(crossprod(L_mat3), Lmu3))
```
## Unbalanced data
$$
[\mathbf{L}^\intercal \bar{\mathbf{Y}}]^\intercal [\mathbf{L}^\intercal \mathbf{W}^{-1} \mathbf{L}]^{-1} [\mathbf{L}^\intercal \bar{\mathbf{Y}}],
$$
where $\mathbf{W}$ is the diagonal matrix of group sizes.
```{r}
set.seed(2203)
num_obs <- c(10, 5, 16, 9)
err <- rnorm(sum(num_obs))
err <- err - ave(err, rep.int(seq_along(num_obs), times = num_obs))
mu <- c(9, 5, 7, 11)
y <- rep(mu, num_obs) + err
group <- rep(LETTERS[1:4], num_obs)
aov(y ~ group)
```
Using `lm`
```{r}
lm1 <- lm(y ~ group)
anova(lm1)
```
Using contrast matrix
```{r}
fac <- factor(group)
contrasts(fac) <- contr.helmert(4)
lm2 <- lm(y ~ fac)
anova(lm2)
```
```{r}
L_mat <- contr.sum(length(mu))
Lmu <- crossprod(L_mat, mu)
crossprod(Lmu, solve(crossprod(L_mat, L_mat / num_obs), Lmu))
```