10-02: One-Sample Z-Tests¶
The framework of 10-01, now with numbers in it. The z-test applies when the sampling distribution of the statistic is normal with a known standard error — for a mean when σ is known, and for a proportion always.
Z-Test for a Mean (σ known)¶
Conditions¶
If σ is unknown — the usual real-world case — use the t-test of 11-01 instead.
Worked Example — Mean¶
A manufacturer claims its batteries last at least 40 hours. A consumer group tests 36 batteries: x̄ = 38.4 hours. The process standard deviation is known to be σ = 4.2. Test at α = 0.05.
STEP 1 H₀: μ ≥ 40 H₁: μ < 40 (left-tailed) α = 0.05
STEP 2 Random sample ✓ σ known ✓ n = 36 ≥ 30 → CLT ✓
STEP 3 SE = σ/√n = 4.2/√36 = 4.2/6 = 0.70
38.4 − 40 −1.6
z = ─────────── = ────── = −2.286
0.70 0.70
STEP 4 Critical value: z₀.₀₅ = −1.645
−2.286 < −1.645 → in the rejection region → REJECT H₀
p-value: P(Z < −2.286) = 0.0111 ≤ 0.05 → REJECT H₀
STEP 5 There is sufficient evidence at the 5% significance level to
conclude that the mean battery life is less than 40 hours.
Confidence-interval cross-check. A one-sided test at α = 0.05 corresponds to a 90% two-sided interval: 38.4 ± 1.645(0.70) = (37.25, 39.55). It lies entirely below 40 — the same conclusion.
Effect size. d = (38.4 − 40)/4.2 = −0.38, a small-to-medium effect. Statistically significant and worth about 1.6 hours of battery life — practically meaningful too.
Z-Test for a Proportion¶
Warning
Use p₀ — the hypothesized proportion — in the standard error, not p̂. This differs from the confidence interval of 09-02, which uses p̂ because there is no hypothesized value to assume. Getting this backwards is the classic error in this section.
Conditions¶
Worked Example — Proportion¶
A company claims 80% of its customers are satisfied. A survey of 250 customers finds 185 satisfied. Is the claim overstated? Test at α = 0.05.
STEP 1 H₀: p ≥ 0.80 H₁: p < 0.80 (left-tailed) α = 0.05
STEP 2 n·p₀ = 250(0.80) = 200 ≥ 5 ✓
n·q₀ = 250(0.20) = 50 ≥ 5 ✓
STEP 3 p̂ = 185/250 = 0.74
SE = √(0.80 × 0.20 / 250) = √0.00064 = 0.025298
0.74 − 0.80 −0.06
z = ───────────── = ───────── = −2.372
0.025298 0.025298
STEP 4 Critical value: −1.645 −2.372 < −1.645 → REJECT H₀
p-value: P(Z < −2.372) = 0.0088 ≤ 0.05 → REJECT H₀
STEP 5 There is sufficient evidence at the 5% level to conclude that
fewer than 80% of customers are satisfied.
Two-Tailed Version¶
Same arithmetic, different decision rule. If the claim had been "the satisfaction rate has changed from 80%":
H₀: p = 0.80 H₁: p ≠ 0.80
Critical values: ±1.96
|−2.372| > 1.96 → REJECT H₀
p-value: 2 × P(Z < −2.372) = 2(0.0088) = 0.0177 ≤ 0.05 → REJECT H₀
A two-tailed p-value is exactly double the one-tailed p-value (for a symmetric distribution). That is why a one-tailed test is more powerful — and why choosing the tail after seeing the data is cheating.
Z-Test for the Difference of Two Proportions¶
(p̂₁ − p̂₂) − 0 x₁ + x₂
z = ─────────────────────────── where p̄ = ───────────
______________________ n₁ + n₂
/ ( 1 1 )
√ p̄ q̄ · ( ── + ── ) (the POOLED proportion,
( n₁ n₂ ) used because H₀ says p₁ = p₂)
Excel¶
' ══ Z-TEST FOR A MEAN ═══════════════════════════════════════════════
' B1 = x̄ = 38.4, B2 = μ₀ = 40, B3 = σ = 4.2, B4 = n = 36, B5 = α = 0.05
=B3/SQRT(B4) ' standard error -> 0.70
=(B1-B2)/(B3/SQRT(B4)) ' z statistic -> -2.28571
=NORM.S.INV(B5) ' left critical value -> -1.64485
=NORM.S.DIST(B7, TRUE) ' left-tailed p-value -> 0.011135
=IF(B9<=B5, "Reject H0", "Fail to reject H0")
' Right-tailed: =1-NORM.S.DIST(z, TRUE)
' Two-tailed: =2*(1-NORM.S.DIST(ABS(z), TRUE))
' From raw data — Z.TEST returns the RIGHT-tailed p-value directly
=Z.TEST(A2:A37, 40, 4.2) ' P(x̄ > 40) — right tail
=1-Z.TEST(A2:A37, 40, 4.2) ' left-tailed p-value
=2*MIN(Z.TEST(A2:A37,40,4.2), 1-Z.TEST(A2:A37,40,4.2)) ' two-tailed
' ══ Z-TEST FOR A PROPORTION ═════════════════════════════════════════
' D1 = x = 185, D2 = n = 250, D3 = p₀ = 0.80, D4 = α = 0.05
=D1/D2 ' p̂ -> 0.74
=SQRT(D3*(1-D3)/D2) ' SE — uses p₀, not p̂ -> 0.0252982
=(D5-D3)/D6 ' z statistic -> -2.37171
=NORM.S.DIST(D7, TRUE) ' left-tailed p-value -> 0.008852
=2*NORM.S.DIST(-ABS(D7), TRUE) ' two-tailed p-value -> 0.017704
=AND(D2*D3>=5, D2*(1-D3)>=5) ' condition check -> TRUE
' ══ DIFFERENCE OF TWO PROPORTIONS ═══════════════════════════════════
' F1=x1, F2=n1, F3=x2, F4=n2
=(F1+F3)/(F2+F4) ' pooled p̄
=SQRT(F5*(1-F5)*(1/F2+1/F4)) ' pooled standard error
=(F1/F2-F3/F4)/F6 ' z statistic
=2*NORM.S.DIST(-ABS(F7), TRUE) ' two-tailed p-value
' ══ Analysis ToolPak ════════════════════════════════════════════════
' Data ▸ Data Analysis ▸ z-Test: Two Sample for Means
' (two-sample only — there is no one-sample z-test dialog)
R¶
# ══ Z-TEST FOR A MEAN ══════════════════════════════════════════════
z_test_mean <- function(xbar, mu0, sigma, n,
alternative = c("two.sided", "less", "greater"),
alpha = 0.05) {
alternative <- match.arg(alternative)
se <- sigma / sqrt(n)
z <- (xbar - mu0) / se
p <- switch(alternative,
less = pnorm(z),
greater = pnorm(z, lower.tail = FALSE),
two.sided = 2 * pnorm(abs(z), lower.tail = FALSE))
list(se = se, z = z, p.value = p,
decision = if (p <= alpha) "Reject H0" else "Fail to reject H0")
}
z_test_mean(38.4, 40, 4.2, 36, "less")
# $se 0.7 $z -2.285714 $p.value 0.01113 $decision "Reject H0"
# From raw data, with the BSDA package
# library(BSDA)
# z.test(battery, mu = 40, sigma.x = 4.2, alternative = "less")
# ══ Z-TEST FOR A PROPORTION ════════════════════════════════════════
z_test_prop <- function(x, n, p0,
alternative = c("two.sided", "less", "greater"),
alpha = 0.05) {
alternative <- match.arg(alternative)
phat <- x / n
se <- sqrt(p0 * (1 - p0) / n) # NOTE: p0, not phat
z <- (phat - p0) / se
p <- switch(alternative,
less = pnorm(z),
greater = pnorm(z, lower.tail = FALSE),
two.sided = 2 * pnorm(abs(z), lower.tail = FALSE))
list(phat = phat, se = se, z = z, p.value = p,
decision = if (p <= alpha) "Reject H0" else "Fail to reject H0")
}
z_test_prop(185, 250, 0.80, "less")
# $phat 0.74 $se 0.0252982 $z -2.371708 $p.value 0.008852 "Reject H0"
# Built-in equivalent (chi-square based — z² = X²)
prop.test(185, 250, p = 0.80, alternative = "less", correct = FALSE)
sqrt(prop.test(185, 250, p = 0.80, correct = FALSE)$statistic) # = |z| = 2.3717
binom.test(185, 250, p = 0.80, alternative = "less") # exact binomial version
# ══ TWO PROPORTIONS ════════════════════════════════════════════════
prop.test(x = c(120, 95), n = c(200, 200), correct = FALSE)
# ══ Visualising the rejection region ═══════════════════════════════
z <- -2.286
curve(dnorm(x), from = -4, to = 4, col = "#5B2A86", lwd = 2,
ylab = "density", main = "Left-tailed test, alpha = 0.05")
xs <- seq(-4, qnorm(0.05), length.out = 200)
polygon(c(-4, xs, qnorm(0.05)), c(0, dnorm(xs), 0),
col = "#0FA3A380", border = NA)
abline(v = z, col = "#0B7A7A", lwd = 2, lty = 2)
text(z, 0.15, "z = -2.286", pos = 2)
Python¶
import numpy as np
from scipy import stats
from statsmodels.stats.proportion import proportions_ztest
from statsmodels.stats.weightstats import ztest
# ══ Z-TEST FOR A MEAN ══════════════════════════════════════════════
def z_test_mean(xbar, mu0, sigma, n, alternative="two-sided", alpha=0.05):
se = sigma / np.sqrt(n)
z = (xbar - mu0) / se
if alternative == "less":
p = stats.norm.cdf(z)
elif alternative == "greater":
p = stats.norm.sf(z)
else:
p = 2 * stats.norm.sf(abs(z))
return {"se": se, "z": z, "p_value": p,
"decision": "Reject H0" if p <= alpha else "Fail to reject H0"}
z_test_mean(38.4, 40, 4.2, 36, "less")
# {'se': 0.7, 'z': -2.2857, 'p_value': 0.011135, 'decision': 'Reject H0'}
# From raw data (statsmodels ztest uses the SAMPLE sd, so it is really a
# large-sample z; supply sigma explicitly with the function above when known)
# ztest(battery, value=40, alternative="smaller")
# ══ Z-TEST FOR A PROPORTION ════════════════════════════════════════
def z_test_prop(x, n, p0, alternative="two-sided", alpha=0.05):
phat = x / n
se = np.sqrt(p0 * (1 - p0) / n) # NOTE: p0, not phat
z = (phat - p0) / se
if alternative == "less":
p = stats.norm.cdf(z)
elif alternative == "greater":
p = stats.norm.sf(z)
else:
p = 2 * stats.norm.sf(abs(z))
return {"phat": phat, "se": se, "z": z, "p_value": p,
"decision": "Reject H0" if p <= alpha else "Fail to reject H0"}
z_test_prop(185, 250, 0.80, "less")
# {'phat': 0.74, 'se': 0.025298, 'z': -2.37171, 'p_value': 0.008852, ...}
# statsmodels (uses p0 in the SE when prop_var is given)
proportions_ztest(count=185, nobs=250, value=0.80,
alternative="smaller", prop_var=0.80)
# (-2.37171, 0.008852)
stats.binomtest(185, 250, p=0.80, alternative="less") # exact binomial
# ══ TWO PROPORTIONS ════════════════════════════════════════════════
proportions_ztest(count=np.array([120, 95]), nobs=np.array([200, 200]))
# ══ Visualising the rejection region ═══════════════════════════════
import matplotlib.pyplot as plt
xs = np.linspace(-4, 4, 500)
crit = stats.norm.ppf(0.05)
fig, ax = plt.subplots()
ax.plot(xs, stats.norm.pdf(xs), color="#5B2A86")
tail = xs[xs <= crit]
ax.fill_between(tail, stats.norm.pdf(tail), color="#0FA3A3", alpha=0.5)
ax.axvline(-2.286, color="#0B7A7A", ls="--")
ax.set_title("Left-tailed test, α = 0.05")
plt.show()
Quick Reference¶
| Test | Statistic | Excel | R | Python |
|---|---|---|---|---|
Mean, σ known |
(x̄−μ₀)/(σ/√n) |
Z.TEST(range, μ₀, σ) |
user function / BSDA::z.test |
user function / ztest |
| Proportion | (p̂−p₀)/√(p₀q₀/n) |
manual formula | prop.test(x, n, p) |
proportions_ztest(..., prop_var=p0) |
| Proportion (exact) | binomial | — | binom.test(x, n, p) |
stats.binomtest(x, n, p) |
| Two proportions | pooled p̄ |
manual formula | prop.test(c(x1,x2), c(n1,n2)) |
proportions_ztest([x1,x2],[n1,n2]) |
| Tail | Critical value | p-value |
|---|---|---|
| Left | NORM.S.INV(α) |
NORM.S.DIST(z, TRUE) |
| Right | NORM.S.INV(1−α) |
1-NORM.S.DIST(z, TRUE) |
| Two | ±NORM.S.INV(1−α/2) |
2*NORM.S.DIST(-ABS(z), TRUE) |
Common Mistakes¶
- Using
p̂instead ofp₀in the standard error of a proportion test. - Forgetting
√nin the denominator of the mean's z-statistic — the single most common slip in the chapter. - Using a z-test when
σis unknown. Uset(11-01). - Halving or doubling the p-value in the wrong direction: two-tailed = 2 × one-tailed.
- Misreading Excel's
Z.TEST, which returns the right-tailed p-value regardless of your alternative. - Comparing
|z|to a negative critical value. - Skipping the
np₀ ≥ 5andnq₀ ≥ 5check.
Exercises: 10-02: Exercises — One-Sample Z-Tests
⬅️ Previous: 10-01: Hypothesis Testing Fundamentals ➡️ Next: 11-01: One-Sample t-Test