Sampling Variability

14.2. Sampling Variability#

Goals

  • Explain sampling variability and why repeated samples differ

  • Visualize sampling distributions with simulation

  • Connect standard error to sample size

  • Recognize law of large numbers behavior

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme()

We will simulate many samples from a Bernoulli process (think weighted coin with \(p=0.6\) for heads) to see how sample proportions vary.

Key quantities:

  • True proportion \(p\)

  • Sample size \(n\)

  • Sample proportion \(\hat p\)

  • Sampling distribution: distribution of \(\hat p\) across repeated samples

rng = np.random.default_rng(seed=0)

p_true = 0.6
n = 40
n_sims = 5_000

# Draw many samples and compute sample proportions
samples = rng.binomial(n=n, p=p_true, size=n_sims)
sample_props = samples / n

summary = pd.Series(sample_props).describe(percentiles=[0.025, 0.5, 0.975]).round(3)
summary
count    5000.000
mean        0.600
std         0.078
min         0.350
2.5%        0.450
50%         0.600
97.5%       0.750
max         0.850
dtype: float64
fig, ax = plt.subplots(figsize=(7, 4))
sns.histplot(sample_props, bins=15, stat="density", color="#4c78a8", edgecolor="white", ax=ax)

ax.axvline(sample_props.mean(), color="#f58518", linestyle="--", label=f"mean = {sample_props.mean():.3f}")
ax.axvline(p_true, color="#54a24b", linestyle=":", label="true p")
ax.set(xlabel="sample proportion", ylabel="density", title="Sampling distribution of p-hat (n=40, p=0.6)")
ax.legend()
plt.show()
../../_images/168f08c1e3fb66c1ed7adb40f8a1b56e77570c5a6306650c43b7366351f2e293.png

For a sample proportion, the standard error measures the typical deviation of \(\hat p\) from \(p\): $\(\text{SE}(\hat p) = \sqrt{\dfrac{p(1-p)}{n}}\)\( If \)p\( is unknown, we often plug in \)\hat p$.

se_theoretical = np.sqrt(p_true * (1 - p_true) / n)
se_empirical = sample_props.std(ddof=1)

print(f"Theoretical SE: {se_theoretical:.4f}")
print(f"Simulated SE:   {se_empirical:.4f}")
Theoretical SE: 0.0775
Simulated SE:   0.0781

Larger samples shrink variability. Below we compare sampling distributions across different \(n\) while keeping \(p=0.6\) fixed.

def simulate_props(n, p=0.6, sims=5_000):
    props = rng.binomial(n=n, p=p, size=sims) / n
    return props

ns = [10, 40, 200]
records = []
frames = []
for n_i in ns:
    props_i = simulate_props(n=n_i)
    frames.append(pd.DataFrame({"n": n_i, "prop": props_i}))
    records.append({
        "n": n_i,
        "mean(p-hat)": props_i.mean(),
        "sd(p-hat)": props_i.std(ddof=1),
        "SE formula": np.sqrt(p_true * (1 - p_true) / n_i)
    })

display(pd.DataFrame(records).round(4))

plot_df = pd.concat(frames, ignore_index=True)
fig, ax = plt.subplots(figsize=(7, 4))
sns.histplot(data=plot_df, x="prop", hue="n", element="step", stat="density", common_norm=False, palette="Dark2", ax=ax)
ax.axvline(p_true, color="black", linestyle=":", label="true p")
ax.set(xlabel="sample proportion", title="Larger n reduces sampling variability")
ax.legend(title="n")
plt.show()
n mean(p-hat) sd(p-hat) SE formula
0 10 0.5994 0.1549 0.1549
1 40 0.5984 0.0780 0.0775
2 200 0.5986 0.0348 0.0346
../../_images/2aae0039037c133b1f9954936bf78c079d3b256a0264ed9a09060725e142a109.png

Takeaways

  • Repeated samples vary; summarizing their distribution clarifies how much.

  • Standard error captures typical sampling fluctuation and shrinks as \(n\) grows.

  • Simulations help check formulas and build intuition about variability.