
One-Way ANOVA in R: A Worked Example
Run a one-way ANOVA in R using a transparent teaching dataset. Inspect the observations, interpret the F test, check assumptions and choose appropriate follow-up comparisons.
On this page
- 1. Decide whether one-way ANOVA fits the question
- 2. Create a small, inspectable dataset
- 3. Plot the observations before testing
- 4. Fit the model and read the ANOVA table
- 5. Inspect model assumptions and residuals
- 6. Use an appropriate follow-up comparison
- 7. Report a result that another person can understand
- Questions readers ask
- Official references and further reading
One-way ANOVA in R compares the means of independent groups using a model with one grouping factor. Running aov() is a small part of the analysis. You also need to decide whether the design fits the method, inspect the data and explain what the result does and does not show.
This tutorial uses a deliberately small teaching dataset so you can inspect every observation. It is not evidence that one training method outperforms another. No real employees, learners or organizations are represented by these numbers.
1. Decide whether one-way ANOVA fits the question
Imagine three independent groups completed a numeric assessment. The question is whether their population mean scores are equal. The outcome is the score; the grouping factor identifies the group. The null hypothesis states that all group means are equal. The alternative is that at least one differs.
A significant overall test does not say which pairs differ, whether every pair differs or whether the difference matters in practice. It also does not show that the group condition caused the result. Causal interpretation needs an appropriate design and attention to how that design was implemented.
If the same people appear in several groups or measurements are clustered within classes, a simple independent-groups analysis may be unsuitable. Before opening R, review how observations were generated. Our data collection methods guide explains why the unit of observation matters.
2. Create a small, inspectable dataset
If you need the software first, follow the R and RStudio installation guide. All functions used in this tutorial come with a standard R installation; you do not need an additional package for the example.
d <- data.frame(
group = factor(rep(c("A", "B", "C"), each = 4)),
score = c(62, 65, 64, 67,
70, 72, 69, 73,
77, 79, 76, 80)
)
str(d)
table(d$group)
aggregate(score ~ group, data = d, FUN = mean)
aggregate(score ~ group, data = d, FUN = sd)
The group means are 64.5, 71.0 and 78.0. Each group has four observations. Explicitly making group a factor communicates that the labels represent categories. A numeric variable containing 1, 2 and 3 could otherwise be treated as a quantitative predictor in a model.
For your own file, check column names, measurement units, impossible values and missing entries before copying the model command. Never change missing observations into zero just to make the function run: zero may be a valid score and changes the meaning of the dataset.
3. Plot the observations before testing
boxplot(score ~ group, data = d,
xlab = "Group", ylab = "Assessment score")
stripchart(score ~ group, data = d,
vertical = TRUE, method = "jitter",
add = TRUE, pch = 16, col = "#1658b9")
Showing individual points matters especially with small groups. A boxplot alone can conceal how few observations support a summary. Inspect differences in spread, unusual observations and the shape of the outcome within groups. An observation should not be deleted merely because its removal produces a preferred p-value.
If a point looks impossible, return to the collection record and document any correction. If it is plausible but unusual, consider how sensitive the result is to that observation and report the issue. Data cleaning and model selection should be explained rather than hidden.
4. Fit the model and read the ANOVA table
fit <- aov(score ~ group, data = d)
summary(fit)
nobs(fit)
For these teaching values, the overall F statistic is approximately 49.73 with numerator and denominator degrees of freedom 2 and 9. The p-value is approximately 0.00001366. Console rounding may display it differently.
| Quantity | Example | Interpretation |
|---|---|---|
| Group degrees of freedom | 2 | Three group means give two independent contrasts |
| Residual degrees of freedom | 9 | Twelve observations minus three estimated group means |
| F statistic | 49.73, approximately | Ratio of between-group to within-group mean squares |
| p-value | 0.00001366, approximately | Evidence against equal means under the model assumptions |
The p-value is not the probability that the null hypothesis is true. Nor does it measure the importance of a difference. In a real project, interpret the size of the score differences in the assessment’s units and consider whether those differences would change a practical decision.
5. Inspect model assumptions and residuals
The standard model assumes independent errors with a common variance and, for its usual exact inference, normally distributed errors. Independence mainly comes from the design; it cannot be confirmed by a residual plot. The NIST one-way ANOVA model reference describes these assumptions.
old_par <- par(mfrow = c(1, 2))
plot(fitted(fit), residuals(fit),
xlab = "Fitted score", ylab = "Residual")
abline(h = 0, lty = 2)
qqnorm(residuals(fit))
qqline(residuals(fit))
par(old_par)
Look for a substantial change in spread between fitted values and conspicuous departures in the normal Q–Q plot. With only twelve observations, diagnostics have limited resolution. A non-significant normality test would not prove that every assumption holds.
If group variances differ substantially and independent-group mean comparison remains the question, consider Welch’s one-way test. In R, oneway.test(score ~ group, data = d, var.equal = FALSE) performs that test. It is not a remedy for dependence, measurement problems or an unsuitable study design.
6. Use an appropriate follow-up comparison
When pairwise comparisons fit the research question and the standard model is defensible, Tukey’s procedure provides adjusted comparisons between group means. R’s TukeyHSD documentation explains its interval and adjusted p-value output.
pairs <- TukeyHSD(fit, "group")
pairs
plot(pairs)
Read the labels carefully. A row labeled B-A represents the estimated mean for B minus the estimated mean for A. Inspect the confidence interval alongside the adjusted p-value. Do not run many unadjusted pairwise tests until a desired comparison appears significant.
If you switch to Welch’s analysis because equal variances are not credible, do not automatically reuse the original standard-model Tukey results. The follow-up method should match the analysis and comparison family. Planned contrasts and exploratory pairwise comparisons also answer different questions.
7. Report a result that another person can understand
An illustrative report could say: “In a constructed dataset with four independent observations per group, a one-way ANOVA gave F(2, 9) = 49.73, p ≈ 0.00001366. Group means were 64.5, 71.0 and 78.0. These values demonstrate the calculation and do not describe an actual intervention.”
For real research, add the sampling or assignment procedure, group sizes, units, variability, diagnostics, missing-data handling and any follow-up comparisons. State whether the analysis was planned. Explain limits to generalization and avoid treating statistical significance as proof of educational or business benefit.
- Confirm the outcome is appropriate for a mean comparison.
- Explain independence and any clustering or repeated measurements.
- Inspect every group’s observations and missing values.
- Check residual behavior and justify the chosen method.
- Use follow-up comparisons that match the research question.
- Report means, uncertainty and practical limitations.
- Save the script and
sessionInfo()with the analysis.
For a question about a continuous predictor rather than a grouping factor, continue with linear regression in R. Choose the model from the study question, not from whichever command is easiest to find.
Questions readers ask
Do I need an extra R package for this ANOVA example?
No. The example uses functions included with a standard R installation.
Does a significant ANOVA mean all groups differ?
No. The overall test supports evidence that at least one population mean differs under the model. Appropriate follow-up comparisons are needed to investigate particular pairs.
What if group variances are unequal?
For a suitable independent-group mean comparison, Welch’s one-way test is an option. It does not fix dependence or an inappropriate study design, and follow-up methods must match the analysis.
Can one-way ANOVA handle repeated measurements automatically?
Not with the simple independent-group model shown here. Repeated measurements or clustered data require a design and analysis that account for their dependence.
Official references and further reading
- R: aov model reference
- NIST: one-way ANOVA model and assumptions
- R: TukeyHSD comparisons
- R: Welch one-way test
Sources checked 19 October 2026. Follow the linked official documents for current software requirements and method details. The examples are educational and do not establish results from an actual study.
Editorial update: Oxford Training and Research. Prepared with AI-assisted drafting; the original author record is retained. Worked examples are illustrative. No independent field study or specialist review is claimed.

