Skip to content

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)

             x̄ − μ₀
z  =  ─────────────────
           σ / √n

Conditions

1.  Random sample
2.  σ is KNOWN
3.  Population normal, OR n ≥ 30 (CLT)

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

             p̂ − p₀                                       x
z  =  ────────────────────           where   p̂  =  ─────
         ____________                                  n
        /  p₀ (1 − p₀)
       √   ────────────
                n

Warning

Use p₀ — the hypothesized proportion — in the standard error, not . This differs from the confidence interval of 09-02, which uses because there is no hypothesized value to assume. Getting this backwards is the classic error in this section.

Conditions

1.  Random sample
2.  n·p₀ ≥ 5   AND   n·(1 − p₀) ≥ 5
3.  n ≤ 0.05 N   (independence)

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 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 instead of p₀ in the standard error of a proportion test.
  • Forgetting √n in the denominator of the mean's z-statistic — the single most common slip in the chapter.
  • Using a z-test when σ is unknown. Use t (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₀ ≥ 5 and nq₀ ≥ 5 check.

Exercises: 10-02: Exercises — One-Sample Z-Tests


⬅️ Previous: 10-01: Hypothesis Testing Fundamentals ➡️ Next: 11-01: One-Sample t-Test