Act I · The tension
Chapter 5 showed us how to fit a regression. But our line \(\hat{y} = b_1 + b_2 x\) comes from one noisy sample. Behind it sits a population line \(\beta_1 + \beta_2 x\) we can never observe.
So why should we trust an estimate we know is wrong? This chapter answers that — with the statistical properties that make OLS the default estimator in econometrics.
OLS is wrong in every sample — but right on average, and we can say exactly how wrong.
Act II · The investigation
To study OLS, the chapter uses generated data where we know the answer:
\[y = \underbrace{1 + 2x}_{E[y\mid x]} + u, \qquad u \sim N(0,\ \sigma_u^2=4)\]
True intercept \(\beta_1=1\), true slope \(\beta_2=2\). The column Eygivenx is the population line exactly; u is the random shock that pulls each observed y off it.
!pip install -q pyfixest # install pyfixest in Colab (-q = quiet; not preinstalled)
import pandas as pd # tabular data
import pyfixest as pf # pyfixest → OLS, R-style formulas
url = "https://raw.githubusercontent.com/quarcs-lab/data-open/master/AED/AED_GENERATEDDATA.DTA"
data = pd.read_stata(url) # 5 points generated from y = 1 + 2x + u
fit = pf.feols("y ~ x", data=data) # OLS: regress observed y on x
fit.coef() # sample estimates b1, b2
fit.summary() # full table: coefs, SEs, t, p, R2Observed points (cyan) scatter around the true population line (purple dashed). The sample line fit to them need not match it.
With only \(n=5\), the estimate (\(b_2=1.05\)) lands far from the truth (\(\beta_2=2\)). This is not a bug — it is sampling variability.
Three independent samples from the identical DGP \(y=1+2x+u\) yield three different fitted lines — all near the true population line, none on it.
Slopes came out 1.81, 1.79, 1.67; intercepts 0.82, 1.75, 2.01. One sample never reveals the truth — it only gives one draw from a distribution of estimates.
import numpy as np # random draws + arrays
import pyfixest as pf # OLS on each simulated sample
np.random.seed(42) # reproducible simulation
n, n_sims = 30, 1000 # 1,000 samples of n = 30
b1_true, b2_true, sigma_u = 1, 2, 2 # the known DGP y = 1 + 2x + u
slopes = [] # collect b2 from each sample
for _ in range(n_sims):
x = np.random.normal(3, 1, n) # draw regressors
u = np.random.normal(0, sigma_u, n) # draw mean-zero errors
y = b1_true + b2_true * x + u # build y from the true model
slopes.append(pf.feols("y ~ x", data=pd.DataFrame({"x": x, "y": y})).coef()["x"])
np.mean(slopes) # ≈ 2.00 → unbiased
np.std(slopes) # ≈ 0.38 → sampling variabilityAcross 1,000 samples, the slope and intercept estimates form bell curves centered on the true values, tracking a normal fit.
Mean slope \(=1.994\) (true \(2\)), SD \(=0.38\); mean intercept \(=0.996\) (true \(1\)). Unbiasedness and asymptotic normality, seen directly.
For a single sample we can’t average over worlds — but we can estimate the spread:
\[s_e=\sqrt{\frac{\text{RSS}}{n-2}}, \qquad se(b_2)=\frac{s_e}{\sqrt{\sum_i (x_i-\bar{x})^2}}\]
Divide RSS by \(n-2\) because two parameters (\(b_1,b_2\)) are estimated. The slope is precise when \(s_e\) is small (good fit) and the \(x\)’s are widely spread.
import numpy as np # arrays + math
import pyfixest as pf # to check our hand calculation
data = pd.DataFrame({"x": [1, 2, 3, 4, 5], # artificial 5-point dataset
"y": [1, 2, 2, 2, 3]})
fit = pf.feols("y ~ x", data=data) # fitted line: y_hat = 0.8 + 0.4x
b1, b2 = fit.coef()["Intercept"], fit.coef()["x"]
data["resid"] = data["y"] - (b1 + b2 * data["x"]) # residuals e = y - y_hat
RSS = np.sum(data["resid"] ** 2) # residual sum of squares
Sxx = np.sum((data["x"] - data["x"].mean()) ** 2) # spread of x
s_e = np.sqrt(RSS / (len(data) - 2)) # standard error of the regression
se_b2 = s_e / np.sqrt(Sxx) # standard error of the slope
print(se_b2, fit.se()["x"]) # hand value == model value ✓In the 108-country convergence data, capital per worker is spread almost as wide as its mean — exactly the condition that estimates the slope precisely.
Act III · The resolution
Objection. “My slope is 1.05 but the truth is 2.0. The method is broken.”
Response. A single wrong estimate is expected, not a failure. Under the four assumptions (correct model, mean-zero errors, homoskedasticity, independence) OLS is unbiased — right on average — and BLUE, the tightest linear unbiased rule. One sample is one draw; the standard error tells you how far it might be off.
Don’t ask “is my estimate exactly right?” Ask “how precise is it?” — that’s what the standard error reports.