Skip to main content

One-way ANOVA

Compare several group means with one test: split the total sum of squares into a part between groups and a part within them, divide each by its degrees of freedom, and read their ratio F against the F distribution. Worked on rent by district and on the iris flowers.
S02.7.3L2 Intermediate25 min
In review (what this means)

The maths and code on this page are checked by automated tests on every change, but an independent reader has not signed it off yet. Spot a mistake or a confusing step? Tell us.

Before this lesson: S02.7.2 Chi-square tests for counts

What you will be able to do
  • Derive the split of the total sum of squares into between-group and within-group parts, and compute both by hand.
  • Form the F statistic from the two mean squares and read its p-value from the F distribution with k - 1 and N - k degrees of freedom.
  • Show that for two groups the F statistic is the square of the pooled t statistic.
  • State the assumptions of one-way ANOVA and explain how a single outlier weakens it.

The question

The nine flats of S01 rent for a mean of 5 in the South, 8 in the North and 17 in the Centre (hundreds of euros). Three groups means three pairs to compare, and three t-tests each at level 0.05 give more than a 5 percent chance of a false alarm. Is there one test that asks “do these means differ at all?” There is, and machine learning uses it to screen thousands of features against a class label in one line.

From the last lesson

1. How are the expected counts of a two-way table found under independence?

Show answer

Row total times column total over the grand total, \({E_{gj} = n_{g\cdot} n_{\cdot j}/n}\); for South with a balcony, \({60 \times 60/120} = 30\).

2. Why does McNemar’s test use only 15 of the 100 test examples?

Show answer

Only the examples on which the two classifiers disagree carry information about which is better; under \(H_0\) each disagreement is a fair coin.

Intuition

Measure how spread out all nine rents are, then ask where that spread comes from. Part of it is between the districts: their means differ. The rest is within them: flats in one district still differ from each other. If the districts truly had the same mean, the between part would be no bigger than the noise the within part shows.

Left panel, Rent in hundreds of euros: three strips of blue dots for South (3, 4, 8), North (7, 7, 10) and Centre (9, 12, 30), each with a vermillion bar at its mean, 5, 8 and 17, and a dashed black line across at the grand mean 10. Thin purple lines join each flat to its district mean, labelled within: a flat to its district mean. Thick vermillion bars join each district mean to the grand mean, labelled between: a district mean to the grand mean. Right panel, Sums of squares: one stacked bar, 234 between in vermillion at the bottom and 278 within in purple on top, total 512.
S02.7.3-F1

Rent by district for the nine flats of S01 (invented). The total sum of squares, 512, splits exactly into 234 between the districts and 278 within them.

Here the within part is larger than the between part. That alone does not settle it, because the two parts rest on different numbers of free values: they are compared per degree of freedom. The comparison is the F statistic, and the method is the analysis of variance, ANOVA.

Build it up

Step 1. The total. Square each rent’s gap to the grand mean 10 and add: the total sum of squares, 512, the figure S01 computed.

Step 2. Split each gap in two. Every flat’s gap to the grand mean is its district’s gap plus its own gap within the district. For the penthouse, \({30 - 10} = {(17 - 10) + (30 - 17)} = 7 + 13\).

Two panels. Left, titled 30 minus 10 equals 7 plus 13: the penthouse at 30 above a dashed grand mean at 10 and a vermillion Centre mean at 17; a thick vermillion segment from 10 to 17 is labelled between 7 and a thick purple segment from 17 to 30 is labelled within 13, beside a thin bracket labelled 20. Right, titled Within gaps add to zero in each group: purple bars for each flat's gap to its district mean: South minus 2, plus 3, minus 1; North minus 1, plus 2, minus 1; Centre minus 5, plus 13, minus 8; each group is labelled sum 0.
S02.7.3-F5

Left: one flat’s gap split into a between part and a within part. Right: inside every group the within gaps cancel, which is what makes the squares add up.

Step 3. Square and add. Squares do not usually add: \({20^2 = 400}\) but \({7^2 + 13^2 = 218}\). Summed over a whole group, though, the cross terms cancel, because the within gaps of a group add to zero. So the sums of squares do add: \({234 + 278 = 512}\).

Step 4. Compare per degree of freedom. Three group means around one grand mean leave 2 free values; nine flats around three group means leave 6. Divide: \({234/2} = 117\) and \({278/6} = 46.33\). Their ratio is \(F = 2.53\).

The formal statement

Write \(k\) groups, \(n_g\) values \(x_{gi}\) in group \(g\), \(N = {\sum_g n_g}\) values in all, group means \(\bar x_g\) and grand mean \(\bar x\).

NoteDefinition: one-way ANOVA

\[ \begin{aligned} SS_T &= \textstyle\sum_g \sum_i (x_{gi} - \bar x)^2 \\ SS_B &= \textstyle\sum_g n_g (\bar x_g - \bar x)^2 \\ SS_W &= \textstyle\sum_g \sum_i (x_{gi} - \bar x_g)^2 \end{aligned} \]

The mean squares are \({MS_B = SS_B/(k - 1)}\) and \({MS_W = SS_W/(N - k)}\), and \(F = {MS_B / MS_W}\). If the groups are independent normal samples with one variance and equal means, \(F\) follows the F distribution \(F_{k-1,\,N-k}\). The p-value is \({\Prob(F_{k-1,N-k} \ge F)}\).

The split, derived. Write each gap as a between part plus a within part and square:

\[ \begin{aligned} (x_{gi} - \bar x)^2 &= (\bar x_g - \bar x)^2 \\ &\quad + 2(\bar x_g - \bar x)(x_{gi} - \bar x_g) \\ &\quad + (x_{gi} - \bar x_g)^2 . \end{aligned} \]

Sum over \(i\) inside group \(g\). The first term does not depend on \(i\), so it gives \({n_g (\bar x_g - \bar x)^2}\). In the middle term the factor \({(\bar x_g - \bar x)}\) comes out of the sum, leaving \({\sum_i (x_{gi} - \bar x_g)} = {n_g \bar x_g - n_g \bar x_g} = 0\). Now sum over \(g\): \(SS_T = SS_B + SS_W\). The degrees of freedom split the same way: \({N - 1} = {(k - 1) + (N - k)}\).

The F distribution. If \(U_1 \sim \chi^2_{\nu_1}\) and \(U_2 \sim \chi^2_{\nu_2}\) are independent, the ratio \({(U_1/\nu_1) / (U_2/\nu_2)}\) has the F distribution \(F_{\nu_1, \nu_2}\). In ANOVA, \({SS_W/\sigma^2}\) is a sum of the independent \({(n_g - 1)s_g^2/\sigma^2}\), each \(\chi^2_{n_g - 1}\) (S02.1.4), so it is \(\chi^2_{N-k}\); under \(H_0\), \({SS_B/\sigma^2}\) is \(\chi^2_{k-1}\) and independent of it (stated). The unknown \(\sigma^2\) cancels in the ratio. With \(k - 1 = 2\) the tail has a closed form, \({\Prob(F_{2,\nu} \ge f)} = {(1 + 2f/\nu)^{-\nu/2}}\); for the flats, \({(1 + 2 \times 2.53/6)^{-3}} = 0.160\).

A blue histogram of 20,000 simulated F statistics, each from three normal groups of three values that share one mean, over an axis from 0 to 8; it is highest at 0 and falls away with a long tail. A black curve, the F distribution on 2 and 6 degrees of freedom, follows it. The area beyond a vermillion line at 2.53 is shaded, labelled observed 2.53: 16.4% of the simulated F reach it, and a pointer to the curve reads F 2,6 curve: 16.0% beyond 2.53.
S02.7.3-F4

When the three districts share one mean, F follows \(F_{2,6}\) exactly (black). In 20,000 simulated sets of nine normal rents (seed 2), 16.4 percent reach the observed 2.53, against 16.0 percent under the curve.

For two groups, \(F = t^2\). Let \(D = {\bar x_B - \bar x_A}\). The grand mean is \({(n_A \bar x_A + n_B \bar x_B)/N}\), so \({\bar x_A - \bar x} = -n_B D/N\) and \({\bar x_B - \bar x} = n_A D/N\). Then

\[ \begin{aligned} SS_B &= n_A \frac{n_B^2 D^2}{N^2} + n_B \frac{n_A^2 D^2}{N^2} \\ &= \frac{n_A n_B (n_A + n_B)}{N^2} D^2 \\ &= \frac{D^2}{1/n_A + 1/n_B} . \end{aligned} \]

With \(k = 2\), \(MS_B = SS_B\), and \(MS_W\) is the pooled variance of S02.7.1, so \({F = D^2 / (s_{\text{pool}}^2 (1/n_A + 1/n_B))} = t^2\). For the two designs, \(F = 3\) and \(t = \sqrt 3\), with the same p-value 0.122.

Assumptions. Independent observations, a normal population in each group, and one shared variance. The flats break the last two: Centre’s standard deviation is 11.4 against 2.6 and 1.7, all because of the penthouse. Lower the penthouse to 15 and \(F\) rises to 5.84, p-value 0.039; raise it to 60 and \(F\) falls to 1.55, p-value 0.29. A more extreme Centre flat makes the test less sure the Centre differs, because the flat inflates the within part more than the between part.

Worked example

Do the three districts differ in mean rent? South 3, 8, 4; North 7, 10, 7; Centre 12, 30, 9.

A flow of boxes. Top: means South 5, North 8, Centre 17; grand mean 10. Arrows lead to two boxes. Left, vermillion: between, 3 times (25 plus 4 plus 49) equals 234, 2 df: mean square 117. Right, purple: within, 14 plus 6 plus 258 equals 278, 6 df: mean square 46.33. Both lead to a yellow box: F equals 117 over 46.33 equals 2.53. Beneath: compared with the F distribution on 2 and 6 df: p-value 0.160.
S02.7.3-F2

One-way ANOVA on the nine flats, from the means to the p-value.

  1. Means: South \({15/3} = 5\), North \({24/3} = 8\), Centre \({51/3} = 17\); grand mean \({90/9} = 10\).
  2. Between: each group has 3 flats, so \(SS_B\) is 3 times the sum of the squared gaps of the district means, \({(5 - 10)^2} = 25\), \({(8 - 10)^2} = 4\) and \({(17 - 10)^2} = 49\): \({3 \times 78} = 234\).
  3. Within. South: \({4 + 9 + 1} = 14\). North: \({1 + 4 + 1} = 6\). Centre: \({25 + 169 + 64} = 258\). So \(SS_W = 278\), and \(234 + 278 = 512\) checks against the total.
  4. Mean squares: \({234/2} = 117\) and \({278/6} = 46.33\). \(F = 2.53\) on 2 and 6 degrees of freedom.
  5. p-value \({(1 + 2 \times 2.525/6)^{-3}} = 0.160\).

At level 0.05 the test does not reject equal means. With three flats per district and one penthouse, it cannot tell the districts apart, even though the Centre mean is more than three times the South mean.

Code

From scratch, then a simulation of \(F\) under \(H_0\).

import numpy as np
from scipy import stats

groups = {"South": [3, 8, 4], "North": [7, 10, 7], "Centre": [12, 30, 9]}   # S01's flats (invented)

def anova(groups):
    arrays = [np.asarray(v, dtype=float) for v in groups]
    every = np.concatenate(arrays)
    grand = every.mean()
    ss_b = sum(len(a) * (a.mean() - grand) ** 2 for a in arrays)
    ss_w = sum(((a - a.mean()) ** 2).sum() for a in arrays)
    k, n = len(arrays), len(every)
    f = (ss_b / (k - 1)) / (ss_w / (n - k))
    return ss_b, ss_w, f, stats.f.sf(f, k - 1, n - k)

ss_b, ss_w, f, p = anova(groups.values())
print(ss_b, ss_w, ss_b + ss_w, round(f, 3), round(p, 3), "closed form:", (1 + 2 * f / 6) ** -3)

rng = np.random.default_rng(2)
sims = rng.normal(0, 1, size=(20_000, 3, 3))                    # 3 groups of 3, one shared mean
means = sims.mean(axis=2)
f_sim = (3 * ((means - sims.mean(axis=(1, 2))[:, None]) ** 2).sum(axis=1) / 2) \
        / (((sims - means[:, :, None]) ** 2).sum(axis=(1, 2)) / 6)
print("simulated share reaching 2.53:", np.mean(f_sim >= f))
234.0 278.0 512.0 2.525 0.16 closed form: 0.16007536649703977
simulated share reaching 2.53: 0.16415

The library call, then the iris flowers as a real case: petal length by species, and f_classif, which computes the same F for every feature column against a class label.

from sklearn.datasets import load_iris
from sklearn.feature_selection import f_classif

res = stats.f_oneway(*groups.values())
print(res.statistic, res.pvalue)

iris = load_iris()
petal = iris.data[:, 2]
by_species = [petal[iris.target == k] for k in range(3)]
print("petal length:", stats.f_oneway(*by_species))
f_all, p_all = f_classif(iris.data, iris.target)
print(dict(zip(iris.feature_names, np.round(f_all, 1))))
2.5251798561151078 0.16007536649703982
petal length: F_onewayResult(statistic=np.float64(1180.1611822529785), pvalue=np.float64(2.8567766109619814e-91))
{'sepal length (cm)': np.float64(119.3), 'sepal width (cm)': np.float64(49.2), 'petal length (cm)': np.float64(1180.2), 'petal width (cm)': np.float64(960.0)}

Petal length gives \(F = 1180\) with 2 and 147 degrees of freedom: the species means 1.46, 4.26 and 5.55 cm are far apart compared with the spread inside each species. Feature screening with SelectKBest(f_classif) keeps the columns with the largest such F.

Explore

S02.7-X1

ANOVA decomposer

Drag any flat up or down, or choose it and use the slider or the minus and plus buttons. Add or remove flats in a district. The bar splits the total sum of squares into between and within, and the read-out gives \(F\) and its p-value. Press Ranks to replace each rent by its rank.

The anchor figure of this lesson: rent for the nine flats as three strips, South, North and Centre, with district means 5, 8 and 17, a grand mean of 10, and a stacked bar splitting the total sum of squares 512 into 234 between and 278 within.

Things to try. Drag the penthouse from 30 up to 60 and then down to 13: \(F\) rises as it comes down, and the p-value crosses 0.05 between 16 and 17. Watch \(H\), the Kruskal-Wallis statistic of S02.7.4, in the read-out as you drag: as long as the penthouse stays the highest rent its rank is 9, so \(H\) does not move. Press Ranks to see why: there the flats are moved with the slider or the buttons, and the penthouse’s dot stays at rank 9. Finally make every district’s flats equal: the within part is 0 and \(F\) has no finite value.

Pitfalls

Two panels. Left, marked with a cross and titled F read alone: a stacked bar of 234 between and 278 within, with the note F equals 2.53, p-value 0.16: rent does not differ. Right, marked with a tick and titled Look at each flat's share first: purple bars of each flat's squared gap to its district mean, labelled by rent and grouped South, North, Centre: 4, 9, 1; 1, 4, 1; 25, 169, 64. The bar for the penthouse, 169, is darker, with the note the penthouse alone gives 169 of the 278.
S02.7.3-F3

Wrong beside right. One F value hides that a single flat supplies most of the within-group spread.

“p-value 0.16, so rent does not differ between districts.”

A large p-value means these nine flats cannot show a difference, not that there is none. Here one flat supplies 169 of the 278 within-group units, the equal-variance assumption fails, and the groups hold three flats each. Plot the groups first, and consider the rank test of S02.7.4.

“F is significant, so every district differs from every other.”

ANOVA asks one question: are all the means equal? A small p-value says at least one differs, not which. Comparing pairs afterwards needs a correction for the several tests, such as Tukey’s method in S02.9.4.

“Three t-tests do the same job as one ANOVA.”

Three tests at level 0.05 each give a family-wise false-alarm chance above 0.05 (S02.9.1). ANOVA spends 0.05 once on the overall question.

Check yourself

Recall

1. What are the between-group and within-group sums of squares for rent by district, and what do they add to?

Show answer

234 and 278, adding to the total 512.

2. Why does \(SS_T = SS_B + SS_W\) hold, when squares do not usually add?

Show answer

The cross term \({2(\bar x_g - \bar x)\sum_i (x_{gi} - \bar x_g)}\) is zero in every group, because the within gaps of a group add to zero.

3. Give \(F\), its degrees of freedom and the p-value for the flats.

Show answer

\({F = 117/46.33} = 2.53\) on 2 and 6 degrees of freedom, p-value 0.160.

4. What is the F distribution?

Show answer

The distribution of \({(U_1/\nu_1)/(U_2/\nu_2)}\) for independent \(U_1 \sim \chi^2_{\nu_1}\) and \(U_2 \sim \chi^2_{\nu_2}\).

5. How are ANOVA’s \(F\) and the pooled two-sample \(t\) related for two groups?

Show answer

\(F = t^2\), with the same p-value: for the two designs \(F = 3\) and \(t = \sqrt 3\).

Exercises

1. ★ Three groups of two: (2, 4), (5, 7) and (8, 12). Compute \(SS_B\), \(SS_W\), \(F\) and the p-value.

Show solution

Means 3, 6 and 10; grand mean \({38/6} = 6.33\). Between:

\[ \begin{aligned} SS_B &= 2\big[(3 - 6.33)^2 \\ &\qquad + (6 - 6.33)^2 \\ &\qquad + (10 - 6.33)^2\big] \\ &= 49.33 . \end{aligned} \]

Within: \({1 + 1} + {1 + 1} + {4 + 4} = 12\). Degrees of freedom 2 and 3, so \({F = (49.33/2)/(12/3)} = 6.17\), and the closed form gives a p-value of \({(1 + 2 \times 6.17/3)^{-1.5}} = 0.087\).

2. ★★ Lower the penthouse’s rent from 30 to 15. Recompute the ANOVA and explain why the p-value falls.

Show solution

Centre becomes 12, 15, 9 with mean 12; the grand mean is \({75/9} = 8.33\). Between:

\[ \begin{aligned} SS_B &= 3\big[(5 - 8.33)^2 \\ &\qquad + (8 - 8.33)^2 \\ &\qquad + (12 - 8.33)^2\big] \\ &= 74 . \end{aligned} \]

Within: \({14 + 6 + 18} = 38\). So \({F = (74/2)/(38/6)} = 5.84\) and the p-value is \({(1 + 2 \times 5.84/6)^{-3}} = 0.039\). The between part shrank from 234 to 74, but the within part shrank far more, from 278 to 38, so the ratio grew.

3. ★★★ Suppose \(H_0\) holds and every group has \(m\) values from a population with variance \(\sigma^2\). Show that \(\E[MS_W] = \sigma^2\) and \(\E[MS_B] = \sigma^2\), so \(F\) should be near 1 under \(H_0\).

Show solution

Within: \(MS_W = {\sum_g (m - 1)s_g^2 / (k(m - 1))}\) is the average of the \(k\) group variances, and each \(s_g^2\) is unbiased for \(\sigma^2\) (S02.2.1), so \(\E[MS_W] = \sigma^2\).

Between: with equal sizes,

\[ MS_B = m \cdot \frac{1}{k - 1}\sum_g (\bar x_g - \bar x)^2 , \]

\(m\) times the sample variance of the \(k\) group means. Under \(H_0\) the group means are independent with common mean \(\mu\) and variance \(\sigma^2/m\), so their sample variance has expectation \(\sigma^2/m\) (S02.2.1 again). Hence \({\E[MS_B] = m \cdot \sigma^2/m} = \sigma^2\). When the true means differ, the group means spread out more and \(MS_B\) grows, while \(MS_W\) does not.

Summary card

Split the spread into between and within, and compare them per degree of freedom.

The anchor figure again: rents of the nine flats in three district strips with means 5, 8 and 17 and grand mean 10, beside a stacked bar of 234 between and 278 within, total 512.
S02.7.3-F1

\(512 = 234 + 278\).

  • Split. \(SS_T = SS_B + SS_W\), and \({N - 1} = {(k - 1) + (N - k)}\).
  • Statistic. \(F = {MS_B / MS_W}\), compared with \(F_{k-1,\,N-k}\).
  • Two groups. \(F = t^2\).
  • Assumptions. Independence, normality, one shared variance; outliers inflate \(SS_W\).

Sources and next steps

Sources. Each was opened and checked against this lesson on 15 November 2026.

Next. S02.7.4 Rank tests replaces values by ranks, which the penthouse cannot pull. Comparisons between pairs of districts after an ANOVA are in S02.9.4.

This lesson unlocks

S02.7.4 Rank tests S02.9.4 Multiplicity in practice

Your progress is saved in this browser only. No account, no tracking.
Back to top