Chapter 61 · Solutions
Why We Sample — Worked Solutions ✅
Five challenges, each verified in code. Try them yourself first.
⚙️ Setup¶
In [1]:
import numpy as np
rng = np.random.default_rng(610)
CHALLENGE 1
The sampling-error law
Draw 2,000 samples of n=50 from Normal(100, 20) and check the observed SE against sigma/sqrt(n).
In [2]:
means = np.array([rng.normal(100,20,50).mean() for _ in range(2000)])
print(f"observed SE = {means.std():.3f}")
print(f"sigma/sqrt(n)= {20/np.sqrt(50):.3f}")
print("match: the standard error of the mean is sigma/sqrt(n)")
observed SE = 2.796 sigma/sqrt(n)= 2.828 match: the standard error of the mean is sigma/sqrt(n)
CHALLENGE 2
The fraction myth
Draw n=200 from a population of 2,000 and from one of 200,000. Show the standard error is essentially the same.
In [3]:
def se(N, n=200, reps=1500):
pop = rng.normal(100, 20, N)
return np.array([rng.choice(pop, n, replace=False).mean() for _ in range(reps)]).std()
print(f"N=2,000 (10% sampled): SE = {se(2_000):.3f}")
print(f"N=200,000 (0.1% sampled): SE = {se(200_000):.3f}")
print("same precision: SE rides on n, not on the fraction n/N")
N=2,000 (10% sampled): SE = 1.322 N=200,000 (0.1% sampled): SE = 1.459 same precision: SE rides on n, not on the fraction n/N
CHALLENGE 3
Bias cannot be outvoted
A convenience method reaches only group A (mean 60); the population is half A, half B (mean 40, true mean 50). Show the estimate stays wrong as n grows.
In [4]:
A = rng.normal(60, 8, 500_000); B = rng.normal(40, 8, 500_000)
pop = np.concatenate([A, B]); print(f"true population mean = {pop.mean():.1f}")
for n in [100, 1000, 50000]:
conv = rng.choice(A, n, replace=False) # only group A is reachable
print(f"convenience sample n={n:>6}: estimate = {conv.mean():.1f} (bias +{conv.mean()-pop.mean():.0f})")
print("more data sharpens the WRONG answer: bias is systematic, not random")
true population mean = 50.0 convenience sample n= 100: estimate = 60.2 (bias +10) convenience sample n= 1000: estimate = 60.0 (bias +10) convenience sample n= 50000: estimate = 60.0 (bias +10) more data sharpens the WRONG answer: bias is systematic, not random
CHALLENGE 4
Quadruple for half
Show the standard error at n=400 is half the standard error at n=100.
In [5]:
pop = rng.normal(100, 20, 1_000_000)
se100 = np.array([rng.choice(pop,100,replace=False).mean() for _ in range(1500)]).std()
se400 = np.array([rng.choice(pop,400,replace=False).mean() for _ in range(1500)]).std()
print(f"SE at n=100: {se100:.3f}")
print(f"SE at n=400: {se400:.3f}")
print(f"ratio = {se400/se100:.2f} (~0.5: 4x the data halves the error)")
SE at n=100: 1.935 SE at n=400: 0.991 ratio = 0.51 (~0.5: 4x the data halves the error)
CHALLENGE 5
Precision per dollar
If measuring one unit costs $1, compare the precision (1/SE) of a census of N=1,000,000 to a sample of n=2,000.
In [6]:
pop = rng.normal(100, 20, 1_000_000)
se_sample = np.array([rng.choice(pop,2000,replace=False).mean() for _ in range(1000)]).std()
prec_sample = 1/se_sample
prec_census = 1/ (20/np.sqrt(1_000_000)) # SE of the full census
print(f"sample n=2,000 : cost $2,000, precision = {prec_sample:.2f}")
print(f"census N=1e6 : cost $1,000,000, precision = {prec_census:.2f}")
print(f"the census costs 500x more for only {prec_census/prec_sample:.1f}x the precision")
sample n=2,000 : cost $2,000, precision = 2.22 census N=1e6 : cost $1,000,000, precision = 50.00 the census costs 500x more for only 22.5x the precision
Statistics, Data Science and AI: A Visual Handbook · © 2026 John Fisher