Understanding interactions

linear-regression
Published

January 28, 2024

Modified

September 23, 2025

x1 <- c("a", "b")
x2 <- c("c", "d")

dat <- expand.grid(id = 1:20, x1 = x1, x2 = x2)
contrasts(dat$x1) <- c(-0.5, 0.5)
contrasts(dat$x2) <- c(-0.5, 0.5)
dat$y <- rnorm(nrow(dat))

# grand mean (intercept)

gm <- mean(aggregate(y ~ x1 + x2, data = dat, mean)$y)

# main effect x1

mx1 <- diff(aggregate(y ~ x1, data = dat, mean)$y)

# main effect x2

mx2 <- diff(aggregate(y ~ x2, data = dat, mean)$y)

# plot

interaction.plot(dat$x1, dat$x2, dat$y, fun = mean)

# interaction x1:x2

int <- aggregate(y ~ x1 + x2, data = dat, mean)
int <- tidyr::pivot_wider(int, names_from = c(x1, x2), values_from = y)
intx1x2 <- (int$a_c - int$a_d) - (int$b_c  - int$b_d)

# model

fit <- lm(y ~ x1 * x2, data = dat)

car::Anova(fit, type = "3")
Anova Table (Type III tests)

Response: y
            Sum Sq Df F value Pr(>F)
(Intercept)  0.063  1  0.0575 0.8111
x1           0.032  1  0.0291 0.8649
x2           0.161  1  0.1479 0.7016
x1:x2        1.852  1  1.6990 0.1964
Residuals   82.834 76               
rbind("model" = coef(fit),
      "manual" = c(gm, mx1, mx2, intx1x2))
       (Intercept)         x11        x21    x11:x21
model    0.0279989 -0.03985257 0.08977371 -0.6085673
manual   0.0279989 -0.03985257 0.08977371 -0.6085673