Confidence interval for a mean
Last updated
A sample mean is a guess at a population mean, and a single guess with no margin around it is hard to act on. A 95 percent confidence interval turns that guess into a range of plausible values for the true mean, carrying a stated level of confidence. This lesson builds the interval from the ground up. Where does a sample mean's variability come from, how do you measure it, and how does the formula change when the sample is small. The running setting is a clinic measuring patients, the kind of estimate you report in a district health office every week.
The sampling distribution of the mean
Imagine you could repeat a study many times. Each time you draw a fresh random sample of the same size from the same population, measure everyone, and compute the sample mean. Those means would not all be equal. They scatter around the true population mean. The sampling distribution of the mean is the distribution of all those sample means.
Two facts about it drive everything else. First, the sample means centre on the population mean , so the sample mean is an unbiased estimate. Second, they spread less than the raw data does, and the spread shrinks as the sample grows. A mean of 100 measurements is steadier than a mean of 4. If the population has mean and standard deviation , the sample mean of observations follows:
The variance of the sample mean is the population variance divided by . That single division by is the reason larger studies give more precise estimates.
The standard error of the mean
The standard deviation of the sampling distribution has its own name: the standard error of the mean, written s.e. It measures how far a typical sample mean falls from the true mean.
You almost never know the population , so you estimate the standard error with the sample standard deviation in its place. Because of the square root, halving the standard error needs four times the sample. Going from to cuts the standard error in half, not to a quarter.
Key term
The standard deviation and the standard error are not the same thing. The standard deviation describes how spread out individual patients are. The standard error describes how spread out sample means are. The standard error is the standard deviation divided by the square root of the sample size, so it is always the smaller of the two. Quote the standard deviation when you are describing people; quote the standard error when you are describing the precision of an estimate.
The central limit theorem
The formula above gives the centre and spread of the sampling distribution, but not its shape. The central limit theorem supplies the shape. It says that whatever the shape of the population, the sampling distribution of the mean tends towards a normal distribution as the sample size grows. Blood pressure is roughly symmetric, hospital length of stay is heavily right-skewed, and yet the mean of a decent-sized sample of either is close to normal.
This is what lets you use the normal distribution to build an interval even when the raw data is not normal. For most distributions a sample of 60 or more is plenty. The more skewed the population, the larger the sample you need before the approximation is good. The simulation below draws samples from a strongly right-skewed population and shows their means piling up into a bell shape.
Draw 2000 sample means from a skewed population and plot their distribution.
set.seed(1) n <- 30 # size of each sample reps <- 2000 # number of samples
# rexp is right-skewed; take the mean of each sample means <- replicate(reps, mean(rexp(n, rate = 1))) # now draw a histogram of means
means <- replicate(reps, mean(rexp(n, rate = 1)))
hist(means, breaks = 30, col = "#4682B4", border = "white",
main = "Sampling distribution of the mean (n = 30)",
xlab = "Sample mean")
abline(v = 1, lwd = 2, lty = 2) # true population mean = 1
cat("mean of means:", round(mean(means), 3),
" se:", round(sd(means), 3), "\n") # se near 1/sqrt(30) = 0.183Draw 2000 sample means from a skewed population and plot their distribution.
import numpy as np import matplotlib.pyplot as plt rng = np.random.default_rng(1) n, reps = 30, 2000
# exponential is right-skewed; take the mean of each sample means = np.array([rng.exponential(1.0, n).mean() for _ in range(reps)]) # now draw a histogram of means
means = np.array([rng.exponential(1.0, n).mean() for _ in range(reps)])
plt.hist(means, bins=30, color="#4682B4", edgecolor="white")
plt.axvline(1.0, color="black", ls="--") # true population mean = 1
plt.title("Sampling distribution of the mean (n = 30)")
plt.xlabel("Sample mean")
plt.show()
print("mean of means:", round(means.mean(), 3),
" se:", round(means.std(ddof=1), 3)) # se near 1/sqrt(30) = 0.183Constructing a 95 percent confidence interval
For a large sample the sampling distribution of the mean is close to normal, and 95 percent of a normal distribution lies within 1.96 standard deviations of its centre. Apply that to the sampling distribution: 95 percent of sample means land within 1.96 standard errors of . Turn that around and you get a 95 percent confidence interval for .
The number 1.96 is the value that cuts off 2.5 percent in each tail of the standard normal distribution. For a 90 percent interval use 1.64; for 99 percent use 2.58. A higher confidence level buys a wider interval, because being more sure of catching the true mean means casting a wider net.
Worked example 1: mean systolic blood pressure
A clinic in Shah Alam measures the systolic blood pressure of 100 randomly selected adult patients. The sample mean is 132 mmHg and the sample standard deviation is 15 mmHg. Estimate the mean systolic pressure of the patient population with a 95 percent interval.
- Standard error: mmHg.
- Margin: mmHg.
- Interval: mmHg.
Report it as a 95 percent CI of 129.1 to 134.9 mmHg. The estimate is the sample mean, 132, and the interval says the true mean is plausibly anywhere from about 129 to 135. With the sample is large, so the normal-based interval is fine and the sample standard deviation is a reliable stand-in for . Verify the arithmetic: the half-width should equal , and as expected.
Build the large-sample 95% CI from summary statistics.
xbar <- 132 # sample mean (mmHg) s <- 15 # sample standard deviation n <- 100 # sample size
se <- s / sqrt(n) # multiply by the 97.5% normal point and add to the mean
se <- s / sqrt(n) # 1.5
z <- qnorm(0.975) # 1.96
ci <- xbar + c(-1, 1) * z * se
cat("se:", se, " margin:", z * se, "\n")
print(round(ci, 2)) # 129.06 134.94Build the large-sample 95% CI from summary statistics.
import numpy as np from scipy.stats import norm xbar, s, n = 132, 15, 100
se = s / np.sqrt(n) # multiply by the 97.5% normal point and add to the mean
se = s / np.sqrt(n) # 1.5
z = norm.ppf(0.975) # 1.96
ci = xbar + np.array([-1, 1]) * z * se
print("se:", se, "margin:", z * se)
print(np.round(ci, 2)) # [129.06 134.94]The clinic doubles the study from 100 to 400 patients and the sample mean and standard deviation come out about the same. Roughly what happens to the width of the 95 percent confidence interval?
The t-distribution and small samples
The large-sample interval leans on a hidden assumption: that is a reliable estimate of . With 100 patients that holds. With 8 patients it does not. A small sample gives a shaky standard deviation, and pretending it is exact makes the interval too narrow and too confident.
The fix is to replace 1.96 with a larger multiplier from the t-distribution. The t-distribution is a bell shape like the normal, but with heavier tails, so its critical values are bigger. The exact shape depends on the degrees of freedom, equal to . Fewer degrees of freedom mean heavier tails and a wider interval, which is the price of the extra uncertainty in . The standardised quantity follows a t-distribution with degrees of freedom, so the interval becomes:
As the sample grows the t-distribution closes in on the normal. The table shows the 95 percent two-sided multiplier at a few degrees of freedom. By around 60 it has nearly reached 1.96, which is why 60 is the usual switch point between the two methods.
| Degrees of freedom (n − 1) | 95% two-sided multiplier t' |
|---|---|
| 5 | 2.571 |
| 9 | 2.262 |
| 29 | 2.045 |
| 60 | 2.000 |
| ∞ (normal) | 1.960 |
W. S. Gosset worked this out while testing beer at Guinness and published under the pen name Student, so you will see it called Student's t-distribution. Strictly the t-method assumes the population is normal, but it holds up well unless the data is severely skewed and the sample is tiny. The central limit theorem covers most of the rest.
When to reach for t versus z
Use the t-distribution whenever you estimate from the sample and the sample is small, say under 60. Use 1.96 from the normal only when the sample is large or is genuinely known beforehand, which is rare in practice. When in doubt, use t. It is never wrong for a mean, and for a large sample it gives almost the same answer as the normal anyway.
Worked example 2: days to fever resolution in dengue
Ten hospitalised dengue patients are followed and the number of days until the fever settles is recorded: 4, 5, 6, 5, 7, 6, 4, 5, 8, 6 days. With only 10 patients this is a small sample, so use the t-distribution.
- Mean: the ten values sum to 56, so days.
- Standard deviation: the sum of squared deviations from 5.6 is 14.40, so and days.
- Standard error: days.
- Multiplier: with 9 degrees of freedom the 95 percent two-sided is 2.262 (from the table).
- Interval: days.
The mean time to fever resolution is 5.6 days, 95 percent CI 4.70 to 6.50 days. Had you wrongly used 1.96, the margin would shrink to , giving 4.82 to 6.38, an interval that looks more precise than the data earns. With a small sample the t-distribution widens the interval on purpose. The block below runs the whole thing with one call to t.test.
Compute the small-sample t-interval from the raw days.
days <- c(4, 5, 6, 5, 7, 6, 4, 5, 8, 6)
# t.test reports the mean and its 95% CI directly t.test(days)
fit <- t.test(days)
cat("mean:", mean(days), " sd:", round(sd(days), 3),
" se:", round(sd(days)/sqrt(length(days)), 3), "\n")
print(round(fit$conf.int, 3)) # 4.695 6.505
# check by hand:
tcrit <- qt(0.975, df = 9) # 2.262
mean(days) + c(-1, 1) * tcrit * sd(days)/sqrt(length(days))Compute the small-sample t-interval from the raw days.
import numpy as np from scipy import stats days = np.array([4, 5, 6, 5, 7, 6, 4, 5, 8, 6])
m = days.mean() se = days.std(ddof=1) / np.sqrt(len(days)) # use the t-distribution for the interval
m = days.mean() # 5.6
se = days.std(ddof=1) / np.sqrt(len(days)) # 0.40
ci = stats.t.interval(0.95, len(days) - 1, loc=m, scale=se)
print("mean:", m, "sd:", round(days.std(ddof=1), 3), "se:", round(se, 3))
print(np.round(ci, 3)) # [4.695 6.505]Interpreting a confidence interval correctly
Here is the careful wording. The true mean is a fixed number, not random. It either sits inside your one interval or it does not. So it is not quite right to say there is a 95 percent probability that lies in this particular interval. The 95 percent describes the method, not the single result you happen to have.
State it like this. If you repeated the study many times and built an interval each time, about 95 percent of those intervals would contain the true mean. Your interval is one draw from a procedure that succeeds 19 times out of 20. The simulation below builds 95 percent intervals from many samples of a population whose mean you know, and counts how often the interval covers it. The figure comes out near 0.95.
Simulate many 95% intervals and measure how often they cover the true mean.
set.seed(7) mu <- 132; sigma <- 15; n <- 30 # known truth reps <- 2000
# for each sample, build a t-interval and test if it covers mu
covers <- replicate(reps, {
x <- rnorm(n, mu, sigma)
ci <- t.test(x)$conf.int
ci[1] <= mu && mu <= ci[2]
})
cat("coverage:", round(mean(covers), 3), "\n") # near 0.95
# draw the first 20 intervals and mark the misses
ci20 <- replicate(20, t.test(rnorm(n, mu, sigma))$conf.int)
miss <- !(ci20[1, ] <= mu & mu <= ci20[2, ])
plot(NA, xlim = c(1, 20), ylim = range(ci20),
xlab = "Sample", ylab = "95% CI for mean SBP")
segments(1:20, ci20[1, ], 1:20, ci20[2, ],
col = ifelse(miss, "#B22222", "#4682B4"), lwd = 2)
abline(h = mu, lty = 2)Simulate many 95% intervals and measure how often they cover the true mean.
import numpy as np from scipy import stats rng = np.random.default_rng(7) mu, sigma, n, reps = 132, 15, 30, 2000
# for each sample, build a t-interval and test if it covers mu
covers = []
for _ in range(reps):
x = rng.normal(mu, sigma, n)
se = x.std(ddof=1) / np.sqrt(n)
lo, hi = stats.t.interval(0.95, n - 1, loc=x.mean(), scale=se)
covers.append(lo <= mu <= hi)
print("coverage:", round(np.mean(covers), 3)) # near 0.95The probability trap
Do not write "there is a 95 percent chance the true mean is between 129 and 135." Once the interval is computed it is fixed, and the true mean is fixed, so the statement has no randomness left in it. The randomness lived in the sampling, before you collected the data. The honest phrasing is about the method: 95 percent of intervals built this way capture the true mean. In a report, "95 percent confident" is the accepted shorthand for exactly that long-run idea.
Not the same as a reference range
A confidence interval and a reference range answer different questions. A 95 percent reference range, , says where 95 percent of individual patients fall. A 95 percent confidence interval, , says where the population mean plausibly sits. For the blood-pressure data the reference range is about 132 plus or minus 29, so roughly 103 to 161 mmHg across patients, while the confidence interval is the tight 129 to 135 for the mean. The confidence interval is always the narrower of the two because it carries the extra division by the square root of n.
A trial reports mean weight gain of 2.0 kg with a 95 percent CI of 0.5 to 3.5 kg in 12 patients. A reviewer says "so 95 percent of patients gained between 0.5 and 3.5 kg." What is wrong?
Common mistakes
- Confusing the standard deviation with the standard error. The standard deviation describes patients; the standard error describes the precision of the mean. Dividing by the square root of n is the difference. Putting the standard deviation into the interval formula gives an interval many times too wide.
- Using 1.96 for a small sample. With fewer than about 60 observations, 1.96 understates the multiplier and the interval comes out too narrow. Use the t-value for n minus 1 degrees of freedom. For n = 10 that is 2.262, not 1.96.
- Reading the 95 percent as a probability about your one interval. The true mean is fixed; the interval is the random part. 95 percent refers to the long-run hit rate of the method, not to a single interval.
- Treating a confidence interval as a reference range. One is about the mean, the other about individuals. The confidence interval is always narrower, by the square root of n.
- Forgetting the central limit theorem has limits. For data that is severely skewed and a sample that is very small, the normal approximation can fail. Transform the scale or use a method built for skewed data instead of forcing a t-interval.
Tips
- Always report the estimate with its interval. "Mean SBP 132 mmHg (95 percent CI 129 to 135)" tells a reader the value and its precision in one line. A bare 132 hides how sure you are.
- Plan sample size from the standard error. Because precision improves with the square root of n, halving the width of an interval costs four times the patients. Decide the width you need before the study, then solve for n.
- Default to t for a single mean. It is never wrong, and for a large sample it matches the normal to three decimals. Let
t.testin R orscipy.stats.t.intervalin Python do the arithmetic so you do not fumble a multiplier. - Check the interval against the question. If the clinically important threshold (say 140 mmHg for hypertension) sits outside your interval, that is a stronger statement than the point estimate alone. The interval, not the mean, is what decides the action.