score brand rep
1 43.9 1 1
2 39.0 1 2
3 46.7 1 3
4 43.8 1 4
5 44.2 1 5
6 47.7 1 6
One-way analysis of variance (ANOVA)
2026-10-26
Data from Kutner et al. (2005).
Ten experimental units assigned to each of four brands of rust inhibitors.
score brand rep
1 43.9 1 1
2 39.0 1 2
3 46.7 1 3
4 43.8 1 4
5 44.2 1 5
6 47.7 1 6
Do the brands differ in effectiveness? Is there a best brand?
| brand | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 43.9 | 39.0 | 46.7 | 43.8 | 44.2 | 47.7 | 43.6 | 38.9 | 43.6 | 40.0 |
| 2 | 89.8 | 87.1 | 92.7 | 90.6 | 87.7 | 92.4 | 86.1 | 88.1 | 90.8 | 89.1 |
| 3 | 68.4 | 69.3 | 68.5 | 66.4 | 70.0 | 68.1 | 70.6 | 65.2 | 63.8 | 69.2 |
| 4 | 36.2 | 45.2 | 40.7 | 40.5 | 39.3 | 40.3 | 43.2 | 38.7 | 40.9 | 39.7 |
Visually compare the treatment group means with boxplots or dotplots.
Start with \(N\) experimental units (EUs), e.g. subjects, mice, etc.
Randomly assign each EU to one of \(a\) treatment groups.
Measure on each EU after treatment a response \(Y\).
Compute the average of the responses in each treatment group
Questions we’d like to answer:
Consider the model
\[ Y_{ij} = \mu + \tau_i + \varepsilon_{ij}, \quad j = 1,\dots,n_i, \quad i = 1,\dots,a, \] where
Of central interest are the hypotheses \[ \text{$H_0$: $\tau_1 = \dots = \tau_a$ \quad versus \quad $H_1$: $\tau_i \neq \tau_{i'}$ for some $i \neq i'$.} \] If we reject \(H_0\), we may wish to sort/compare the treatments.
An alternate version of the model is
\[ Y_{ij} = \mu_i + \varepsilon_{ij}, \quad j = 1,\dots,n_i, \quad i = 1,\dots,a, \] where
In this version of the model the central hypotheses become \[ \text{$H_0$: $\mu_1 = \dots = \mu_a$ \quad versus \quad $H_1$: $\mu_i \neq \mu_i'$ for some $i \neq i'$}. \]
In the one-way treatment effects model \[ Y_{ij} = \mu + \tau_i + \varepsilon_{ij}, \quad j = 1,\dots,n_i, \quad i = 1,\dots,a, \] where \(\varepsilon_{ij}\overset{\operatorname{ind}}{\sim}\mathcal{N}(0,\sigma^2)\), we wish to
Treatment group means: \(\displaystyle \bar Y_{i.} = \frac{1}{n_i}\sum_{j=1}^{n_i} Y_{ij}\), \(i=1,\dots,a\).
Treatment group standard deviations: \(\displaystyle S_i = \frac{1}{n_i - 1}\sum_{j=1}^{n_i}(Y_{ij} - \bar Y_{i.})^2\), \(i=1,\dots,a\).
Overall mean: \(\displaystyle \bar Y_{..} = \frac{1}{N}\sum_{i=1}^a\sum_{j=1}^{n_i} Y_{ij}\), where \(N = n_1 + \dots + n_a\).
Here we use the convention of placing a “.” in the position of an index over which we have taken the sum.
| brand | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | \(\bar Y_{i.}\) | \(S_i\) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 43.9 | 39.0 | 46.7 | 43.8 | 44.2 | 47.7 | 43.6 | 38.9 | 43.6 | 40.0 | 43.14 | 3.000 |
| 2 | 89.8 | 87.1 | 92.7 | 90.6 | 87.7 | 92.4 | 86.1 | 88.1 | 90.8 | 89.1 | 89.44 | 2.218 |
| 3 | 68.4 | 69.3 | 68.5 | 66.4 | 70.0 | 68.1 | 70.6 | 65.2 | 63.8 | 69.2 | 67.95 | 2.169 |
| 4 | 36.2 | 45.2 | 40.7 | 40.5 | 39.3 | 40.3 | 43.2 | 38.7 | 40.9 | 39.7 | 40.47 | 2.436 |
The mean of all response values was \(\bar Y_{..} = 60.25\).
We would like estimators \(\hat \mu\) and \(\hat \tau_1,\dots,\hat \tau_a\) of \(\mu\) and \(\tau_1,\dots,\tau_a\) which satisfy \[\begin{align*} \hat \mu + \hat \tau_1& = \bar Y_{1.} \\ \hat \mu + \hat \tau_2& = \bar Y_{2.} \\ &\vdots \\ \hat \mu + \hat \tau_a& = \bar Y_{a.} \end{align*}\]
However, we cannot uniquely determine the values of \(\hat \mu\) and \(\hat \tau_1,\dots,\hat \tau_a\) from the above because there are only \(a\) equations (and \(a+1\) unknowns).
A way out is to simply set \(\hat \tau_1 = 0\) (the default strategy in R).
Setting \(\hat \tau_1 = 0\) gives \[\begin{align*} \hat \mu & = \bar Y_{1.} \\ \hat \mu + \hat \tau_2& = \bar Y_{2.} \\ &\vdots \\ \hat \mu + \hat \tau_a& = \bar Y_{a.} \end{align*}\]
After rearranging we obtain \[\begin{align*} \hat \mu & = \bar Y_{1.} \\ \hat \tau_2& = \bar Y_{2.} - \bar Y_{1.} \\ &\vdots \\ \hat \tau_a& = \bar Y_{a.} - \bar Y_{1.} \end{align*}\]
So \(\hat \tau_2,\dots,\hat \tau_a\) represent differences in the mean from the first or “baseline” treatment group.
For the rust inhibitor data we have \(\bar Y_{1.} = 43.14\), \(\bar Y_{2.} = 89.44\), \(\bar Y_{3.} = 67.95\), and \(\bar Y_{4.} = 40.47\), so we set \[\begin{align*} \hat \mu & = 43.14 \\ \hat \mu + \hat \tau_2& =89.44 \\ \hat \mu + \hat \tau_3& =67.95 \\ \hat \mu + \hat \tau_4& =40.47. \end{align*}\]
Rearranging gives \[\begin{align*} \hat \mu & = 43.14 \\ \hat \tau_2& = 89.44 - 43.14 = 46.3\\ \hat \tau_3& = 67.95 - 43.14 = 24.81\\ \hat \tau_4& = 40.47 - 43.14 = -2.67. \end{align*}\]
Use lm() with as.factor() to fit the one-way ANOVA model.
As in linear regression, define the
for \(j=1,\dots,n_i\), \(i = 1,\dots,a\).
Then an unbiased estimator of \(\sigma^2\) is given by \[ \hat \sigma^2 = \frac{1}{N-a} \sum_{i=1}^a (n_i - 1)S_i^2 =\frac{1}{N - a} \sum_{i=1}^a\sum_{j=1}^{n_i} \hat \varepsilon_{ij}^2. \] So \(\hat \sigma^2\) pools the group variances into a single estimate.
Divide by \(N-a\) since the \(N\) residuals depend on \(a\) estimated quantities
Consider how to compute \(\hat \sigma^2\) from the data below:
| brand | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | \(\bar Y_{i.}\) | \(S_i\) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 43.9 | 39.0 | 46.7 | 43.8 | 44.2 | 47.7 | 43.6 | 38.9 | 43.6 | 40.0 | 43.14 | 3.000 |
| 2 | 89.8 | 87.1 | 92.7 | 90.6 | 87.7 | 92.4 | 86.1 | 88.1 | 90.8 | 89.1 | 89.44 | 2.218 |
| 3 | 68.4 | 69.3 | 68.5 | 66.4 | 70.0 | 68.1 | 70.6 | 65.2 | 63.8 | 69.2 | 67.95 | 2.169 |
| 4 | 36.2 | 45.2 | 40.7 | 40.5 | 39.3 | 40.3 | 43.2 | 38.7 | 40.9 | 39.7 | 40.47 | 2.436 |
One obtains \(\hat \sigma^2 = 6.14\).
The value of \(\hat \sigma\) is printed in the summary() output:
Call:
lm(formula = score ~ as.factor(brand), data = rust)
Residuals:
Min 1Q Median 3Q Max
-4.270 -1.597 0.395 1.275 4.730
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 43.140 0.784 55.06 <2e-16 ***
as.factor(brand)2 46.300 1.108 41.78 <2e-16 ***
as.factor(brand)3 24.810 1.108 22.39 <2e-16 ***
as.factor(brand)4 -2.670 1.108 -2.41 0.021 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 2.48 on 36 degrees of freedom
Multiple R-squared: 0.986, Adjusted R-squared: 0.985
F-statistic: 866 on 3 and 36 DF, p-value: <2e-16
As in linear regression we decompose the variation in the \(Y_{ij}\) by defining:
We have \(\operatorname{SS}_{\operatorname{Tot}} = \operatorname{SS}_{\operatorname{Trt}} + \operatorname{SS}_{\operatorname{Error}}\).
Note that \(\operatorname{SS}_{\operatorname{Trt}}\) is computed just like \(\operatorname{SS}_{\operatorname{Reg}}\) in linear regression.
We again define \(\displaystyle R^2 = \frac{\operatorname{SS}_{\operatorname{Trt}}}{\operatorname{SS}_{\operatorname{Tot}}}\).
The SS, appropriately scaled, follow chi-square distributions:
where \(\phi_{\operatorname{Tot}}\) and \(\phi_{\operatorname{Trt}}\) are noncentrality parameters.
Dividing \(\operatorname{SS}_{\operatorname{Trt}}\) and \(\operatorname{SS}_{\operatorname{Error}}\) by their dfs, we define:
The ratio \(\displaystyle \operatorname{F}_{\operatorname{test}}= \frac{\operatorname{MS}_{\operatorname{Trt}}}{\operatorname{MS}_{\operatorname{Error}}}\) has an F distribution.
We often present the SS, df, and MS values in a table like this:
| Source | Df | SS | MS | F value | p-value |
|---|---|---|---|---|---|
| Treatment | \(a-1\) | \(\operatorname{SS}_{\operatorname{Trt}}\) | \(\operatorname{MS}_{\operatorname{Trt}}\) | \(\operatorname{F}_{\operatorname{test}}\) | \(P(F > \operatorname{F}_{\operatorname{test}})\) |
| Error | \(N-a\) | \(\operatorname{SS}_{\operatorname{Error}}\) | \(\operatorname{MS}_{\operatorname{Error}}\) | ||
| Total | \(N-1\) | \(\operatorname{SS}_{\operatorname{Tot}}\) |
In the table \(\displaystyle \operatorname{F}_{\operatorname{test}}= \frac{\operatorname{MS}_{\operatorname{Trt}}}{\operatorname{MS}_{\operatorname{Error}}}\).
The p-value is based on \(F \sim F_{a-1,N-a}\).
Obtain the ANOVA table “manually”:
Y <- rust$score
Y.. <- mean(Y)
Yi. <- aggregate(score ~ brand, mean, data = rust)[,2]
nn <- aggregate(score ~ brand, length, data = rust)[,2]
a <- length(Yi.)
N <- sum(nn)
SStot <- sum((Y - Y..)**2)
SStrt <- sum(nn*(Yi. - Y..)**2)
SSerror <- SStot - SStrt
MStrt <- SStrt / (a - 1)
MSerror <- SSerror / (N - a)
Ftest <- MStrt / MSerror
pval <- 1 - pf(Ftest, a-1, N - a)Consider how to compute \(\operatorname{SS}_{\operatorname{Trt}}\) from the data. Use the fact that \(\bar Y_{..} = 60.25\).
| brand | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | \(\bar Y_{i.}\) | \(S_i\) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 43.9 | 39.0 | 46.7 | 43.8 | 44.2 | 47.7 | 43.6 | 38.9 | 43.6 | 40.0 | 43.14 | 3.000 |
| 2 | 89.8 | 87.1 | 92.7 | 90.6 | 87.7 | 92.4 | 86.1 | 88.1 | 90.8 | 89.1 | 89.44 | 2.218 |
| 3 | 68.4 | 69.3 | 68.5 | 66.4 | 70.0 | 68.1 | 70.6 | 65.2 | 63.8 | 69.2 | 67.95 | 2.169 |
| 4 | 36.2 | 45.2 | 40.7 | 40.5 | 39.3 | 40.3 | 43.2 | 38.7 | 40.9 | 39.7 | 40.47 | 2.436 |
Obtain the ANOVA table with the anova() function on the lm() output.
In the one-way treatment effects model we wish to test \[ \text{$H_0$: $\tau_1 = \dots = \tau_a$ \quad versus \quad $H_1$: $\tau_i \neq \tau_{i'}$ for some $i \neq i'$.} \]
We use the overall F test of significance:
The value of \(\displaystyle \operatorname{F}_{\operatorname{test}}\) and the p-value are printed in the summary() output.
Note that \(\operatorname{F}_{\operatorname{test}}\) is a ratio of the form \(\displaystyle \frac{\text{Between treatment variation}}{\text{Within treatment variation}}\).
For which data set will the F-statistic be largest/smallest?
In the cell-means formulation of the model \[ Y_{ij} = \mu_i + \varepsilon_{ij}, \quad j = 1,\dots,n_i, \quad i = 1,\dots,a, \] where \(\mu_i = \mu + \tau_i\), we have the following CI formulas:
| Target | \((1-\alpha)100\%\) confidence interval |
|---|---|
| \(\mu_i\) | \(\bar Y_{i.} \pm t_{N-a,\alpha/2}\hat \sigma \sqrt{\frac{1}{n_i}}\) |
| \(\mu_i - \mu_{i'}\) | \(\bar Y_{i.} - \bar Y_{i'.} \pm t_{N-a,\alpha/2}\hat \sigma \sqrt{\frac{1}{n_i} + \frac{1}{n_{i'}}}\) |
Compute 95% CIs for \(\mu_1\) and \(\mu_2 - \mu_1\).
A 95% CI for \(\mu_1\) is \([41.551,44.729]\).
A 95% CI for \(\mu_2 - \mu_1\) is \([44.053,48.547]\).
If we reject \(H_0\): \(\mu_1 = \dots = \mu_a\), then we may wish to compare means.
Call such comparisons post-hoc as we do them after the F-test.
We may wish to compare several pairs of means, which is like testing several hypotheses at once.
When several hypotheses are tested at once, the familywise Type I error rate is the probability that any Type I error is committed.
We discuss two methods for post-hoc comparisons of means which control the familywise Type I error rate.
We want to build a CI for \(\mu_i - \mu_{i'}\) for all pairs \(i \neq i'\).
Suppose the design is balanced, i.e. \(n_i = n\) for all \(i = 1,\dots,a\).
If we build for all \(i \neq i'\) the ordinary \((1-\alpha)\times 100\%\) CIs \[ \bar Y_{i.} - \bar Y_{i'.} \pm t_{a(n-1),\alpha/2} \hat \sigma \sqrt{2/n}, \] each one will cover its target with probability \(1-\alpha\).
But now we want simultaneous coverage with probability \(1-\alpha\), i.e. \[ P(\cap_{i \neq i'} \{\text{CI for $\mu_i - \mu_{i'}$ captures target}\}) = 1-\alpha. \]
Above probability is called the familywise coverage.
John Tukey, 1915 – 2000
Suppose the design is balanced, i.e. \(n_i = n\) for all \(i = 1,\dots,a\).
Suppose we could find the value \(q_{a,a(n-1),\alpha}\) such that \[ P\left(\max_{i \neq i'} \left\{ \frac{|(\bar Y_{i.} - \bar Y_{i'.}) - (\mu_i - \mu_{i'}) |}{\hat \sigma /\sqrt{n}}\right\} \leq q_{a,a(n-1),\alpha} \right) = 1-\alpha. \]
Then with probability \(1-\alpha\) the CIs \[ \bar Y_{i.} - \bar Y_{i'.} \pm q_{a,a(n-1),\alpha} \hat \sigma / \sqrt{n} \] will simultaneously cover the targets \(\mu_i - \mu_{i'}\) for all \(i \neq i'\). Show!
Tukey made tables of the values \(q_{a,a(n-1),\alpha}\).
Can use the simultaneous intervals to sort/compare the means.
Table A.6 from Mohr, Wilson, and Freund (2021)
For the rust data we have \(n = 10\) and \(a = 4\).
At \(\alpha = 0.05\) we have \(q_{a,a(n-1),\alpha} = q_{4,36,0.05} \approx 3.85\) from table.
Obtain exact value with qtukey(.95,4,36) = 3.809.
Build the Tukey HSD CI for \(\mu_2 - \mu_1\).
We obtain the interval \([43.316,49.284]\).
Use TukeyHSD() on aov() output to obtain the simultaneous CIs.
Tukey multiple comparisons of means
95% family-wise confidence level
Fit: aov(formula = score ~ as.factor(brand), data = rust)
$`as.factor(brand)`
diff lwr upr p adj
2-1 46.30 43.32 49.284 0.000
3-1 24.81 21.83 27.794 0.000
4-1 -2.67 -5.65 0.314 0.093
3-2 -21.49 -24.47 -18.506 0.000
4-2 -48.97 -51.95 -45.986 0.000
4-3 -27.48 -30.46 -24.496 0.000
It may be that not all pairwise comparisons are of interest.
Then Tukey’s method is too conservative (CIs wider than necessary).
Say we want to compare all treatments to a “baseline” treatment.
Build CIs for \(\mu_i - \mu_1\), \(i = 2,\dots,a\), \(1\) the baseline treatment.
This makes \(a-1\) CIs instead of \({a\choose 2}\) CIs.
Can use Dunnett’s method, Dunnett (1964).
Charles Dunnett, 1921 – 2007 (Canadian, served in WWII, photo taken in Belgium)
Assume \(n_i = n\) for all \(i\) (balanced case).
Given a value \(d_{a,a(n-1),\alpha}\) such that \[ P\left( \max_{2 \leq i \leq a} \Big| \frac{(\bar Y_{i.} - \bar Y_{1.}) - (\mu_i - \mu_1)}{\hat \sigma\sqrt{2/n}} \Big| \leq d_{a,a(n-1),\alpha}\right) = 1 - \alpha, \] with probability \(1-\alpha\) the CIs \[ \bar Y_{i.} - \bar Y_{1.} \pm d_{a,a(n-1),\alpha} \hat \sigma\sqrt{2/n} \] will simultaneously cover the targets \(\mu_i - \mu_1\) for all \(i=2,\dots,a\).
Dunnett made tables of the values \(d_{a,a(n-1),\alpha}\).
Cannot sort all the means after Dunnett’s.
Table A.5 from Mohr, Wilson, and Freund (2021)
For the rust data we have \(n = 10\) and \(a = 4\).
At \(\alpha = 0.05\) we have \(d_{a,a(n-1),\alpha} = d_{4,36,0.05}\).
Use value \(2.44\) in the table (should be close).
Treat Brand 1 as the baseline and make comparisons with Dunnett’s.
The \(95\%\) Dunnett’s CI for \(\mu_2 - \mu_1\) is \([43.596,49.004]\).
Follow the same procedure for the other comparisons.
Use DunnettTest() from R package DescTools.
Dunnett's test for comparing several treatments with a control :
95% family-wise confidence level
$`1`
diff lwr.ci upr.ci pval
2-1 46.30 43.58 49.0175 <2e-16 ***
3-1 24.81 22.09 27.5275 <2e-16 ***
4-1 -2.67 -5.39 0.0475 0.0549 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
If building \(m\) CIs you can ALWAYS use the Bonferroni correction:
Compare Brand 3 to 4 and Brand 1 to 3, using the Bonferroni correction to control the familywise error rate.
lower upper
3-4 24.9 30.1
1-3 -27.4 -22.2
Validity of the foregoing analyses depends on these assumptions:
The responses are normally distributed around the treatment means (Check QQ plot of residuals).
The response has the same variance in all treatment groups (Check residuals vs fitted values plot).
The response values are independent of each other (No way to check; must trust experimental design).
Do axis re-scalings affect how we perceive an x-y relationship?
For a single data set with data pairs \((X_i,Y_i)\), with \(X_i \sim \mathcal{N}(0,1)\) and \(Y_i = \mathcal{N}(X_i,1)\) for \(i = 1,\dots,50\), three scatterplot treatments were constructed:
Each student in a class was randomly assigned a scatterplot and told to draw with a ruler the best-fitting line through the data. The slope of each student-drawn line was measured and recorded as the response.
Is the response mean the same in the three treatment groups?
An artifact from each treatment group:
Call:
lm(formula = slope ~ as.factor(trt))
Residuals:
Min 1Q Median 3Q Max
-0.922 -0.285 -0.129 0.263 1.348
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.3686 0.1816 7.54 2.1e-07 ***
as.factor(trt)X 0.0514 0.2487 0.21 0.84
as.factor(trt)Y 0.1737 0.2421 0.72 0.48
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.48 on 21 degrees of freedom
Multiple R-squared: 0.0261, Adjusted R-squared: -0.0666
F-statistic: 0.282 on 2 and 21 DF, p-value: 0.757
Checks if the mean magnitude of the residuals is equal across groups:
So, do the ordinary F-test with the \(|\hat \varepsilon_{ij}|\) as the responses.
Perform Levene’s test:
Call:
lm(formula = abs(ehat) ~ as.factor(trt))
Residuals:
Min 1Q Median 3Q Max
-0.2914 -0.1277 -0.0498 0.0822 0.7986
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.2098 0.0935 2.24 0.036 *
as.factor(trt)X 0.0502 0.1281 0.39 0.699
as.factor(trt)Y 0.3393 0.1247 2.72 0.013 *
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.247 on 21 degrees of freedom
Multiple R-squared: 0.303, Adjusted R-squared: 0.237
F-statistic: 4.57 on 2 and 21 DF, p-value: 0.0226
Can also use the leveneTest() function in the R package car.
Levene's Test for Homogeneity of Variance (center = mean)
Df F value Pr(>F)
group 2 4.57 0.023 *
21
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
We conclude that the variances are not equal across treatment groups.