BasicIndependently reviewed, not yet spot-checked by a human

t-tests and analysis of variance

What the normality assumption actually assumes, why Welch belongs as the default, what changes when the data are paired, which multiple comparisons follow an ANOVA, and why testing for normality before choosing a test is a bad habit.

What this method solves

You have a continuous outcome (birth weight, blood pressure, length of stay) and a grouping variable. The question is always the same sentence: is the gap between the groups too large to be sampling luck?

The t-test and analysis of variance (ANOVA) are the same idea at two scales. Both compute one ratio:

statistic=gap between groupsuncertainty of that gap\text{statistic} = \frac{\text{gap between groups}}{\text{uncertainty of that gap}}

The denominator of a t-test is the standard error of the difference; the denominator of an ANOVA is the within-group variation. Once the numerator has been divided by it, what you hold is “how many units wide is this gap, measured with this dataset’s own noise as the ruler”. The p-value is only the last step that converts that number into a probability.

This page uses MASS::birthwt: 189 mothers recorded at a hospital in Springfield, Massachusetts in 1986, with newborn birth weight in grams as the outcome.

What the normality assumption actually assumes

The assumption is often compressed into “a t-test does not assume the data are normal”. It has three layers, and running them together is where the error creeps in:

  1. The exact-inference layer really is an assumption about the data. The t statistic follows a t distribution exactly in a small sample only when the observations within each group — more precisely, the model’s errors — are exactly normal. Real data is at best approximately normal, so the distribution is approximate too. A paired t-test assumes that the paired differences are approximately normal, not that each of the two measurements is.
  2. Welch relaxes a different assumption. What the Welch t-test drops is equality of the two variances; it leaves the normality assumption exactly where it was.
  3. Only a large enough sample makes that layer matter less. When observations are independent and the distribution has finite variance, the central limit theorem (CLT) drives the sampling distribution of the mean (or of the mean difference) towards normal, so mild to moderate skewness in the raw data is usually not fatal. Small samples, extreme outliers, and very heavy tails still distort the inference.

So the question worth asking is not “are the data normal” but “given my n and the shape of this distribution, is the normal approximation good enough”. The third layer can be demonstrated: resample serum bilirubin from survival::pbc (skewness 2.7, with a very long right tail) and watch the distribution of the sample mean move towards normal:

Four panels. The leftmost shows the raw distribution of serum bilirubin, strongly right-skewed. The other three show the distribution of sample means for samples of 5, 30, 60 observations, with skewness falling panel by panel and the shape approaching the normal curve drawn over it.
The leftmost panel is the raw data. The three to its right are the distribution of the sample mean over 5000 repeated samples, with the matching normal curve in green. Raw skewness is 2.7; by n = 60 the skewness of the mean is down to 0.37.Plotting script figures/scripts/B1-02-t-test-anova.R
What is being sampledSkewness of its distribution
Raw data (one patient at a time)2.7
Mean of a sample of n = 51.18
Mean of a sample of n = 300.47
Mean of a sample of n = 600.37

So the working rule in practice is not “run a normality test and see whether it is significant”, but:

  • Small n (a dozen or so per group) and a visibly skewed distribution → the p-value may be unreliable; consider a non-parametric method, or lead with the confidence interval for the difference.
  • Moderate n or more (tens per group) → the t-test is usually quite robust even when the raw data are skewed.
  • Extreme outliers → this is the genuinely dangerous case. The CLT converges far more slowly against outliers than against skewness, and the mean itself may no longer be the summary you wanted.

Welch should be the default

R’s t.test() defaults to var.equal = FALSE, that is, to the Welch t-test, and that default is right. Student’s t-test asks for one extra condition — equal variances in the two groups — and that condition:

  • almost never holds exactly in real data;
  • cannot safely be checked with a test (var.test(), Levene’s test) without walking into the trap described in the section on testing for normality first, below;
  • distorts the type I error rate of the Student version when it fails, especially with unequal group sizes.

Welch does not need the condition. The price is fractional degrees of freedom and a negligible loss of power. Unequal variances are the normal state of affairs and equal variances the special case, so the default should match the normal state, not the special case.

With the data on this page the variance ratio is 1.3 and the two calculations reach the same conclusion:

tdfp95% CI for the difference (g)
Welch (the default)2.73170.10.00779–489
Student (equal variances)2.651870.00973–495

The difference is tiny, and that is precisely the point: Welch costs you almost nothing and removes an assumption you would otherwise have to defend. There is no reason to take that assumption on to recover a sliver of power.

Running it yourself

library(MASS)
data(birthwt, package = "MASS")

birthwt$smoke_f <- factor(birthwt$smoke, levels = c(0, 1),
                          labels = c("Non-smoker", "Smoker"))
birthwt$race_f  <- factor(birthwt$race, levels = 1:3,
                          labels = c("White", "Black", "Other"))

# Two independent groups: Welch (the default)
t.test(bwt ~ smoke_f, data = birthwt)

# Paired: the same people measured twice
# Since R 4.4 the formula interface rejects paired=TRUE
# (error: cannot use 'paired' in formula method)
data(sleep)
t.test(Pair(sleep$extra[sleep$group == 2],
            sleep$extra[sleep$group == 1]) ~ 1)

# Three groups or more: one-way ANOVA + Tukey post hoc
fit <- aov(bwt ~ race_f, data = birthwt)
summary(fit)
TukeyHSD(fit)

# Non-parametric counterparts (badly skewed distribution and small n)
wilcox.test(bwt ~ smoke_f, data = birthwt)     # Mann-Whitney U
kruskal.test(bwt ~ race_f, data = birthwt)     # Kruskal-Wallis

Verified with R 4.6.0 and MASS 7.3.65. t.test() is already Welch by default — do not add var.equal = TRUE just to match a textbook.

Three panels. A plots birth weight for smoking and non-smoking mothers as individual points with the group mean and its 95% confidence interval. B shows box plots of birth weight by the three recorded race groups with the ANOVA result. C shows the three Tukey HSD pairwise differences with their family-wise confidence intervals against a vertical line at zero.
A: birth weight split by maternal smoking; the diamond is the group mean and the thick line its 95% confidence interval. B: box plots by recorded race group with the one-way ANOVA. C: Tukey HSD pairwise comparisons; an interval crossing zero means no statistically significant difference was detected.Plotting script figures/scripts/B1-02-t-test-anova.R

The smoking group has 74 mothers with a mean of 2771.9 g (SD 659.6); the non-smoking group has 115 with a mean of 3055.7 g (SD 752.7). The difference is 283.8 g, 95% CI 79–489 g, p = 0.007, Cohen’s d = 0.4.

Paired or independent: the same numbers, two conclusions

What separates paired from independent data is not what the numbers look like, but whether the two columns are linked one to one: the same person before and after, the same person’s left and right eye, a matched case-control design. When the link exists you must use the paired version, because pairing removes person-to-person variation entirely and what remains is far quieter.

The soporific data Student analysed in 1908 (datasets::sleep, 10 subjects each trying both drugs, collected by Cushny and Peebles) shows it. Both analyses are fed exactly the same 20 numbers:

AnalysisMean difference (hours)95% CItdfp
Paired t-test (correct)1.580.70–2.464.0690.003
Independent-samples t-test (wrong)1.58-0.21–3.371.8617.80.079

The point estimate is identical, yet the p-value moves from 0.003 to 0.079. The reason is that the two measurements correlate at 0.8 — people who sleep a lot anyway sleep a lot on either drug. The paired analysis subtracts that individual difference out and looks only at each person’s own change; the SD of the differences is just 1.23, against raw group SDs of 1.79 and 2.

Two panels. A is a slope graph with the two drugs on the horizontal axis and extra hours of sleep on the vertical axis; each of the 10 subjects contributes one connecting line, 9 sloping up, 1 flat and 0 sloping down, together occupying -1.6 to 5.5 hours vertically, with a thick dashed line joining the two group means. B reduces the same data to 10 drug-two-minus-drug-one differences, ranging from 0 to 4.6, plotted as points against a horizontal line at zero, with a diamond and thick bar to the right showing the mean difference of 1.58 and its 95% confidence interval, 0.70 to 2.46, the whole interval sitting above zero.
A: one line per subject; the lines start at very different heights yet almost all run the same way. B: the same numbers reduced to the single column the paired test is actually run on, each person's own difference.Plotting script figures/scripts/B1-02-t-test-anova.R

Those lines on the left are what the paired test looks at. Of the 10 subjects, 9 slept longer on the second drug, 0 slept less, and 1 did not move at all. Vertically the lines occupy -1.6 to 5.5 hours, so people differ enormously from one another, yet each line runs almost the same way — and that direction only becomes visible once the two points are joined. The independent-samples analysis takes the two columns apart and sees two clouds of widely scattered points (SD 1.79 and 2), so the shared direction is counted as noise. The paired analysis collapses each line into one difference first (panel B); the differences run from 0 to 4.6, their scatter is down to an SD of 1.23, and the 95% confidence interval around their mean of 1.58 hours, 0.70–2.46, sits entirely above zero. The same direction is signal under one analysis and noise under the other.

ANOVA and the multiple comparisons that follow it

With three groups or more, running three pairwise t-tests lets type I error accumulate: across three independent comparisons the probability of at least one false positive is 14.3%, and across ten it is 40.1%. ANOVA puts an omnibus test in front, asking once whether all the group means are equal, and keeps the multiplicity outside the door.

For the three recorded race groups the result is F(2, 186) = 4.91, p = 0.008, η2\eta^2 = 0.05 — meaning this variable accounts for 5% of the total variation in birth weight.

Tukey HSD is the most common post hoc method, and what it controls is the family-wise error rate:

ComparisonMean difference (g)Tukey 95% CIAdjusted pUnadjusted p
Black-White-383-756.2 to -9.80.0430.012
Other-White-297.4-566.2 to -28.70.0260.011
Other-Black85.6-304.5 to 475.60.8620.579

The gap between the last two columns is the price of the adjustment: for Black vs White the unadjusted p is 0.012 and the adjusted one is 0.043, sitting right against 0.05. A paper that reports only unadjusted pairwise p-values without saying so has quietly inflated its type I error rate.

A few practical points:

  • Decide the post hoc comparisons in advance. “All pairs” and “each group against the control only” need different adjustments; the latter has more power with Dunnett’s test.
  • Do not treat “only do pairwise tests if the ANOVA is significant” as a licence to skip adjustment (this is Fisher’s LSD). Beyond three groups it no longer protects the family-wise error rate.
  • If the primary hypothesis was always about one specific pair, run that comparison directly and write it into the protocol; there is no need to pass through an ANOVA first.

Why “test for normality first, then decide” is a bad habit

A common workflow runs Shapiro-Wilk first, uses a t-test if p > 0.05 and switches to Wilcoxon if p < 0.05. It has three problems, and the first is fatal.

The power of a normality test varies with n in exactly the wrong direction. Draw repeated samples from one fixed skewed distribution (Gamma(shape = 2, rate = 1), skewness = 1.41), 2000 times each:

Sample size per groupProportion Shapiro-Wilk calls non-normalActual type I error rate of the Welch t-test
n = 2052.4%0.052
n = 500100.0%0.050

Same distribution throughout. At n = 20 Shapiro flags only about half the samples (52.4%), so close to half the time it waves you through to a t-test; at n = 500 it flags 100.0%, so you switch to a non-parametric method every time. Yet the Welch t-test’s actual type I error rate sits on the nominal 0.05 in both cases — the workflow waves you through when there is something to worry about and stops you when there is not.

The other two problems:

  • A two-stage procedure distorts the final error rate. The p-value you report was computed conditional on the outcome of the first test, so its distribution is no longer the one you think it is.
  • It hands the choice of method to the data. What analysis to run should follow from the design and the question, written down in advance, not picked after seeing the result.

The right approach: decide from the nature of the variable in advance — for quantities that are right-skewed by nature (length of stay, costs, biomarker concentrations), plan from the outset to report medians and use non-parametric methods or a transformation — then use a histogram and a Q-Q plot to confirm the data have no unexpected shape. Do not use a test as a switch.

Common misuses

MisuseWhy it is wrong
Testing for normality first to decide whether to use a t-testIts power moves with n in the wrong direction, and the two-stage procedure distorts the final error rate
Setting var.equal = TRUE “to match the textbook”Equal variance is the special case; Welch drops an assumption at almost no cost in power
Using an independent-samples t-test on before-and-after measurementsThrows away the variance reduction pairing bought; in the example here p moves from 0.003 to 0.079
Running three pairwise t-tests across three groups without adjustmentThe family-wise error rate climbs to 14.3%, and to 40.1% over ten comparisons
Reporting a p-value without the difference and its confidence intervalThe reader can judge neither the clinical meaning of the gap nor how precisely it was estimated
Reading a significant omnibus test as “every group differs”F says only “not all equal”; which pair differs is a question for the post hoc comparisons
Comparing means of a strongly right-skewed variable anywayThe type I error rate may be fine, but the mean has stopped being a meaningful summary
Saying “the two groups did not differ” because p > 0.05Only that this study did not detect a difference; claiming equivalence needs an equivalence design with a pre-specified margin
Treating a small η2\eta^2 as proof the test was wrongSignificance and explained variation are different things; report both

Reproducing every number on this page

/opt/homebrew/bin/Rscript figures/scripts/B1-02-t-test-anova.R

Read the figure

The answer comes from the same statistical output that produced this page's figures, not from a number typed in beside them.

The same sleep data, analysed two ways on exactly the same 20 numbers. Both give a point estimate of 1.58 hours, but the paired t-test gives p = 0.0028 and the independent-samples t-test gives p = 0.0794. Where does the difference come from?

Show the answer and why

Correct answer: The paired test works on each subject's own difference, and that column has a standard deviation of only 1.23 hours, because person-to-person variation has been subtracted out entirely

The point estimate is identical either way; what changes is where the noise comes from. The raw columns are each widely spread (the second drug column has a standard deviation of 2.00 hours), because people who sleep a lot sleep a lot on both drugs - that is what the correlation of 0.80 is saying. The paired analysis first collapses each person to one difference, and that column has a standard deviation of just 1.23, so the shared direction turns from noise into signal. A high correlation does not mean counting anyone twice; the opposite, in fact, since it is precisely a high correlation that makes ignoring the pairing throw power away. Nor is the wider second column about an unstable drug: that spread is between people, not between drugs. Forcing a paired analysis onto independent data is equally wrong and much harder to spot, because it manufactures power out of nothing.

A reviewer asks you to test whether the two variances are equal and to use Student's t-test if they are. In this page's comparison of birth weight by maternal smoking, the variance ratio is 1.3. How should you answer?

Show the answer and why

Correct answer: Welch gives p = 0.007, near enough identical to Student's version, and Welch carries one fewer assumption to defend at almost no cost in power

The two procedures agree on this data, 0.007 against 0.009, and that is the point: Welch costs almost nothing and removes an assumption you would otherwise have to defend. The variance test gives 0.225, which looks like a pass, but using a test as a switch walks into the same trap as testing for normality first - its power tracks the sample size, so the situations that should worry you are waved through, and small unequal-sized groups are exactly where the type I error rate of Student's version goes astray. As for it making no difference which is the default, a default should match the common case: in real data two variances are almost never exactly equal, and equality is the special case.

Repeated sampling from one fixed skewed distribution: at 20 per group Shapiro-Wilk calls the sample non-normal 52.4% of the time, and at 500 per group it does so 100% of the time. What does that say about testing for normality before choosing a test?

Show the answer and why

Correct answer: At n = 500 the actual type I error rate of Welch is still 0.050, right on nominal - the procedure waves through the case that should worry you and blocks the case that should not

Small samples are where the normal approximation might not be good enough, and that is where Shapiro-Wilk lets nearly half of them through. Large samples are where the central limit theorem has already brought the sampling distribution of the mean close to normal, and there the test stops almost every one of them, at a rate of 1.000. The actual type I error rate of Welch sits on nominal in both settings, 0.052 and 0.050, and the 0.052 is simulation noise rather than evidence of anything exceeding nominal. So the question worth asking is not whether the data are normal but whether the normal approximation is good enough given this sample size and this shape - decided in advance from the nature of the variable. The two-stage procedure has a second problem too: the p value you report is computed conditional on the first test, and its distribution is no longer the one you think it is.

Birth weight compared across three groups: the overall F test gives p = 0.0083. In the Tukey table, the Black versus White row has an unadjusted p of 0.0117 and an adjusted p of 0.0428. Which should the paper report?

Show the answer and why

Correct answer: Report 0.0428: it accounts for the fact that three comparisons were made at once

The adjusted 0.0428 sits right against the conventional level while the unadjusted 0.0117 looks comfortable, and the gap between those last two columns is what the adjustment costs. Treating a significant overall test as a licence to skip adjustment is Fisher’s LSD, which stops protecting the family-wise error rate beyond three groups, and three independent comparisons already carry a 14.3% chance of at least one false positive. 0.8624 is the adjusted p of a different comparison and does not set the error rate for the set: Tukey widens the threshold for each comparison separately rather than taking the largest. Two practical points follow. Post hoc comparisons should be specified in advance, since all pairwise comparisons and comparisons against a single control need different adjustments; and when the primary hypothesis already names two groups, run that comparison, write it into the protocol, and skip the omnibus test.

The overall F test for maternal race is significant, and the same block of output also prints eta squared. Which number tells you how much race matters for birth weight?

Show the answer and why

Correct answer: Eta squared, 0.05. Race explains only a small share of the total variation

The F statistic of 4.91 and the p value of 0.01 both encode effect size and sample size at once: with a large enough n, a tiny effect still produces a large F, which is why F is not an effect size. Eta squared of 0.05 is: race accounts for a small share of the total variation in birth weight, and the overwhelming majority of it comes from elsewhere. A significant F says only that the group means are not all the same. It does not say which groups differ, which needs post hoc comparisons, and it does not say whether the difference matters clinically, which needs an effect size and a confidence interval for the difference. Report a p value with no difference and no interval and the reader can judge neither the clinical meaning nor the precision.

The mean birth weight difference between smokers and non-smokers is 283.8 grams, and the paper says only that p = 0.007 and the smoking group is significantly lighter. Which number is missing if you want to judge clinical importance?

Show the answer and why

Correct answer: The lower limit of the 95% confidence interval for the difference, 79 grams - it answers how small the difference could be and still fit this data

A p value says the difference is too large to look like sampling luck; it does not say how large. The point estimate of 283.8 grams is the best single answer, but judging clinical importance means asking how small the interval will allow the difference to be, and the lower limit is 79 grams. If 79 grams is already clinically meaningless in your setting, this significant result supports no decision. The 74 smokers are one reason the interval has the width it has, but a sample size is not an effect size, and the non-smoker mean of 3056 grams is a baseline that also fails to answer how small the difference could be. The mirror-image rule applies when nothing is significant: write that this study did not detect a difference, because claiming the groups are equivalent needs an equivalence design and a margin fixed in advance.

Watch next

醫學統計 EP10 t 檢定與非參數法
繁中EDMAN MURMURS· 10 minTraditional Chinese, written for clinicians. Ten minutes covering the t-test alongside its non-parametric alternatives.
醫學統計 EP11 ANOVA
繁中EDMAN MURMURS· 14 minThe sequel to the previous video — what ANOVA compares, and why it is not the same as running many t-tests.
醫學統計 EP04 標準差與標準誤
繁中EDMAN MURMURS· 14 minIf the difference between SD and SE is not solid, the confidence interval and central limit theorem sections here will be hard going. Watch this first.
生物統計學一 45.【型一與型二錯誤】
繁中臺大開放式課程 NTU OCW· 4 minA four-and-a-half minute unit from National Taiwan University's open courseware on type I and type II error — the accumulating type I error is exactly what the multiple comparisons section uses.

Sources and licences

This page is original writing

Report a content problem

The statistics on this site are written by AI and reviewed by AI; a human only spot-checks. What you can see may be what we cannot.

The more specific, the more fixable — e.g. which sentence disagrees with which textbook or paper.

Needed only if you want a reply; reports without it are still read.

Sent along with your report

These are attached automatically. You can drop any of them.