Act I · The tension
You survey 30 people and get an average income of $52,000. Someone else surveys a different 30 and gets $48,000. Who is right?
Both. Each \(\bar{x}\) is one realization of a random variable \(\bar{X}\) that changes from sample to sample. This chapter asks: what does the distribution of \(\bar{X}\) look like — and how do we use it?
The number you compute is random; its distribution is what inference is built on.
Act II · The investigation
A fair coin has \(\mu = 0.5\) and \(\sigma^2 = 0.25\). Toss it 30 times, record the fraction of heads — that’s one \(\bar{x}\). Do it 400 times and you can watch the sampling distribution emerge.
\[\bar{X} = \frac{1}{n}\sum_{i=1}^{n} X_i, \qquad E[\bar{X}] = \mu, \qquad \operatorname{Var}[\bar{X}] = \frac{\sigma^2}{n}\]
The textbook pre-computed the 400 means for us — let’s load and summarize them first.
import pandas as pd # pandas → load & handle tabular data
import numpy as np # numpy → sqrt and array math
url = "https://raw.githubusercontent.com/quarcs-lab/data-open/master/AED/AED_COINTOSSMEANS.DTA"
data = pd.read_stata(url) # 400 sample means, each from n = 30 tosses
xbar = data["xbar"] # the column of 400 sample means
print(xbar.mean()) # empirical E[X̄] → 0.5004
print(xbar.std()) # empirical SD → 0.0887
print(np.sqrt(0.25 / 30)) # theoretical σ/√n → 0.0913
data.describe().round(4) # full summary of the 400 meansEach bar counts how often a sample mean landed in that range; the curve is the theoretical \(N(\mu,\,\sigma^2/n)\).
The histogram of sample means is the sampling distribution — centered at \(\mu\), spread \(\sigma/\sqrt{n}\).
Larger samples don’t shift the center — they shrink the spread. The catch: it shrinks with \(\sqrt{n}\), not \(n\).
| \(n\) | \(\sigma/\sqrt{n}\) |
|---|---|
| 10 | 0.158 |
| 30 | 0.091 |
| 100 | 0.050 |
| 400 | 0.025 |
| 1000 | 0.016 |
To halve the standard error you must quadruple the sample size — precision is expensive.
import numpy as np # numpy → random draws + arrays
np.random.seed(10101) # fix the seed → reproducible result
means = np.zeros(400) # container for 400 sample means
for i in range(400): # repeat the experiment 400 times
sample = np.random.binomial(1, 0.5, 30) # 30 fair coin tosses (each 0 or 1)
means[i] = sample.mean() # store this sample's mean X̄
print(means.mean()) # ≈ 0.50 → unbiased
print(means.std()) # ≈ 0.091 → matches σ/√n1880 U.S. Census ages are heavily right-skewed (\(\mu = 24.13\), \(\sigma = 18.61\)). Yet the means of 100 samples of \(n = 25\) trace a familiar bell.
100 sample means of 1880 census ages — a bell curve rising from a skewed population.
The CLT: average enough draws and \(\bar{X}\) goes normal — whatever the population’s shape.
import numpy as np, pandas as pd # arrays + data
import matplotlib.pyplot as plt # plotting
from scipy.stats import norm # scipy → the normal pdf for the overlay
url = "https://raw.githubusercontent.com/quarcs-lab/data-open/master/AED/AED_COINTOSSMEANS.DTA"
xbar = pd.read_stata(url)["xbar"] # the 400 coin-toss sample means
fig, ax = plt.subplots(figsize=(10, 6)) # one figure + axes
ax.hist(xbar, bins=20, density=True, # empirical sampling distribution
color="#008CB7", alpha=0.75) # (density so it compares to a pdf)
grid = np.linspace(xbar.min(), xbar.max(), 200)
ax.plot(grid, norm.pdf(grid, 0.5, np.sqrt(0.25 / 30)), # theoretical N(μ, σ²/n)
color="#C21E72", lw=3) # DataPink curve on top
plt.show() # render histogram + normal overlayUnbiased, efficient, consistent — this is why the sample mean is the workhorse estimator.
Act III · The resolution
Objection. “More data always gets me closer to the truth.”
Response. Only under simple random sampling. Oversample one group — say 70% women when the population is 50/50 — and the plain mean is biased, no matter how large \(n\) is. The fix is a weighted mean with inverse-probability weights \(w_i = 1/\pi_i\), which restores the true population average.
Consistency assumes a representative sample; a biased design converges to the wrong number.