Asymptotic foundations
¶

Alfred Galichon (NYU)
¶

'math+econ+code' masterclass series: econometrics
¶

CLT, CMT, Slutsky, and a first confidence interval
¶

© 2018–2026 by Alfred Galichon. Past and present support from NSF grant DMS-1716489, ERC grant CoG-866274 are acknowledged, as well as inputs from contributors listed here.

If you reuse material from this masterclass, please cite as:
Alfred Galichon, 'math+econ+code' masterclass series. https://www.math-econ-code.org/

Learning objectives¶

  • Use the Central Limit Theorem (CLT) to derive the asymptotic distribution of sample averages, and read the Berry–Esseen theorem as a statement about its rate of convergence.

  • Combine the CLT with the Continuous Mapping Theorem (CMT) and Slutsky's theorem to deduce the asymptotic distribution of derived statistics such as the studentized sample mean.

  • Assemble these tools into an asymptotic confidence interval for a population mean, and benchmark it against the exact-Gaussian ($t_{I-1}$) interval on real data.

This lecture continues directly from Lecture 1 (conditional expectations, modes of convergence, and the Law of Large Numbers).

References¶

[H] Hansen, B. E. (2022). Econometrics. Princeton University Press. Chapters 5–6. Online at https://users.ssc.wisc.edu/~bhansen/econometrics/.

[vdV] van der Vaart, A. W. (1998). Asymptotic Statistics. Cambridge University Press.

[CB] Casella, G., and Berger, R. L. (2002). Statistical Inference, 2nd edition. Duxbury.

[M] Mroz, T. A. (1987). 'The Sensitivity of an Empirical Model of Married Women's Hours of Work to Economic and Statistical Assumptions'. Econometrica, 55(4), 765–799.

Motivation: completing the asymptotic toolkit¶

Lecture 1 introduced the conditional expectation function, the modes of convergence, and the Law of Large Numbers: the statement that a sample average converges to its population counterpart. The LLN tells us where an estimator settles; it says nothing about the shape of its sampling distribution or how to build a confidence interval.

We shall now introduce the remaining tools. The Central Limit Theorem gives the Gaussian shape of a centered, rescaled sample average; the Continuous Mapping Theorem and Slutsky's theorem propagate that shape through the smooth transformations that turn a raw average into a usable statistic. We keep the same simulation-first approach, and close by assembling all four tools into an asymptotic confidence interval on the Mroz (1987) log-wage data introduced in Lecture 1.

Loading our libraries¶

We start with the standard scientific Python stack.

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import stats

rng = np.random.default_rng(777)
plt.rcParams['figure.figsize'] = (8, 4.5)

Loading our data¶

We use Mroz's (1987) cross-section of $I=753$ married women, of whom $428$ report a positive hourly wage. The dataset is hosted as a CSV on Vincent Arel-Bundock's Rdatasets repository, which mirrors the standard R packages used in econometrics teaching. (If the URL is unreachable, an offline alternative is pip install wooldridge followed by wooldridge.data('mroz'), modulo a small column-name change: in that variant the labor-force-participation indicator is inlf rather than lfp.)

In [2]:
url = 'https://vincentarelbundock.github.io/Rdatasets/csv/sampleSelection/Mroz87.csv'
try:
    mroz = pd.read_csv(url)                       # Rdatasets Mroz87 (needs a network)
except Exception:
    # Offline fallback: the identical Mroz (1987) data ships with the `wooldridge` package.
    import wooldridge
    mroz = (wooldridge.data('mroz')
            .rename(columns={'inlf': 'lfp', 'kidslt6': 'kids5', 'kidsge6': 'kids618'})
            .copy())
print(f'Number of observations: {len(mroz)}')
print(f'Working women (lfp=1):  {(mroz["lfp"]==1).sum()}')
mroz.head(3)
Number of observations: 753
Working women (lfp=1):  428
Out[2]:
lfp hours kids5 kids618 age educ wage repwage hushrs husage ... faminc mtr motheduc fatheduc unem city exper nwifeinc lwage expersq
0 1 1610 1 0 32 12 3.3540 2.65 2708 34 ... 16310.0 0.7215 12 7 5.0 0 14 10.910060 1.210154 196
1 1 1656 0 2 30 12 1.3889 2.65 2310 30 ... 21800.0 0.6615 7 7 11.0 1 5 19.499981 0.328512 25
2 1 1980 1 3 35 12 4.5455 4.04 3072 40 ... 21040.0 0.6915 12 7 5.0 0 15 12.039910 1.514138 225

3 rows × 22 columns

For the rest of the lecture we restrict attention to working women, for whom the hourly wage wage is positive and observed. We also create the log-wage variable lwage.

In [3]:
mroz_w = mroz.loc[mroz['lfp'] == 1].copy()
mroz_w['lwage'] = np.log(mroz_w['wage'])
print(f'I = {len(mroz_w)}')
print(mroz_w[['wage', 'lwage', 'educ', 'exper']].describe().round(2))
I = 428
         wage   lwage    educ   exper
count  428.00  428.00  428.00  428.00
mean     4.18    1.19   12.66   13.04
std      3.31    0.72    2.29    8.06
min      0.13   -2.05    5.00    0.00
25%      2.26    0.82   12.00    7.00
50%      3.48    1.25   12.00   12.00
75%      4.97    1.60   14.00   18.00
max     25.00    3.22   17.00   38.00

1. The Central Limit Theorem¶

1.1 Statement¶


Theorem (Lindeberg–Lévy CLT). If $(X_i)_{i\geq 1}$ are i.i.d. with $\mathbb{E}[X_1]=\mu$ and $\operatorname{Var}(X_1)=\sigma^2\in(0,\infty)$, then $$ \sqrt{I}\,(\bar X_I - \mu)\xrightarrow{d} \mathcal{N}(0,\sigma^2). $$


The CLT explains the universality of the normal distribution in econometrics: as long as the underlying random variables have a finite second moment, the sampling distribution of any sample mean, appropriately re-centered and re-scaled, looks Gaussian.

1.2 Simulation across parent distributions¶

For four very different parent distributions, we draw $M=20\,000$ Monte Carlo samples of size $I$, compute the studentized sample mean $$ Z_I^{(m)} := \frac{\sqrt{I}\,\bigl(\bar X_I^{(m)}-\mu\bigr)}{\sigma}, $$ and overlay its histogram against the standard normal density.

In [4]:
def clt_simulation(sampler, mu, sigma, I=200, R=20_000):
    X_r_i = sampler(size=(R, I))     # R Monte Carlo samples (r in [R]) of I individuals (i in [I])
    mean_r = X_r_i.mean(axis=1)
    Z_r = np.sqrt(I) * (mean_r - mu) / sigma
    return Z_r

specs_clt = {
    'Uniform(0,1)':       (lambda size: rng.random(size), 0.5,  np.sqrt(1/12)),
    'Exponential(1)':     (lambda size: rng.exponential(1.0, size), 1.0, 1.0),
    'Bernoulli(0.1)':     (lambda size: (rng.random(size) < 0.1).astype(float), 0.1, np.sqrt(0.1*0.9)),
    'Lognormal(0,1)':     (lambda size: rng.lognormal(0.0, 1.0, size), np.exp(0.5), np.sqrt((np.exp(1)-1)*np.exp(1))),
}

I = 200
R = 20_000
S = len(specs_clt)
Z_s_r = np.empty((S, R))
for s, (_, (sampler, mu, sigma)) in enumerate(specs_clt.items()):
    Z_s_r[s] = clt_simulation(sampler, mu, sigma, I=I, R=R)

z_g = np.linspace(-4, 4, 400)
In [5]:
fig, axes = plt.subplots(2, 2, figsize=(11, 6.5))
for s, (ax, name) in enumerate(zip(axes.flat, specs_clt)):
    ax.hist(Z_s_r[s], bins=60, density=True, alpha=0.55, edgecolor='white')
    ax.plot(z_g, stats.norm.pdf(z_g), 'k-', lw=1.5, label=r'$\mathcal{N}(0,1)$')
    ax.set_xlim(-4, 4)
    ax.set_title(f'{name},  I = {I}')
    ax.legend(loc='upper right', fontsize=9)
plt.tight_layout()
plt.show()
No description has been provided for this image

The Bernoulli(0.1) panel illustrates that the CLT requires $I$ to be large relative to the non-normality of the parent distribution. The quantity that governs the rate is not skewness but the standardized third absolute moment $\rho/\sigma^3$ with $\rho = \mathbb{E}\lvert X-\mu\rvert^3$, which appears in the Berry–Esseen bound below. The two are different: a symmetric but heavy-tailed parent has zero skewness and can still have a large $\rho/\sigma^3$, and so a slow approach to normality. In this particular panel the parent does happen to be skewed: with success probability 0.1, the sampling distribution of the mean is still visibly discrete and right-skewed at $I=200$. The Berry–Esseen theorem, stated next, makes this precise.

1.3 Rate of convergence: the Berry–Esseen theorem¶

The CLT tells us that $Z_I=\sqrt{I}(\bar X_I-\mu)/\sigma \xrightarrow{d}\mathcal{N}(0,1)$, but on its own it says nothing about how fast. The Berry–Esseen theorem supplies a uniform, non-asymptotic rate.


Theorem (Berry–Esseen). Let $(X_i)_{i\ge 1}$ be i.i.d. with mean $\mu$, variance $\sigma^2\in(0,\infty)$, and finite third absolute moment $\rho:=\mathbb{E}\lvert X_1-\mu\rvert^3<\infty$. Then, with $\Phi$ the standard-normal CDF, $$ \sup_{x\in\mathbb{R}}\bigl\lvert\,\mathbb{P}(Z_I\le x)-\Phi(x)\,\bigr\rvert \;\le\; \frac{C\,\rho}{\sigma^3\,\sqrt{I}}, $$ where $C$ is an absolute constant: the same for every distribution (the best known value is $C<0.4748$).


Two readings of the bound:

  • Rate. The worst-case (Kolmogorov) distance between the exact sampling distribution and its Gaussian limit vanishes like $I^{-1/2}$; halving the error takes roughly four times as much data.
  • Constant. It is proportional to the standardized third absolute moment $\rho/\sigma^3$. This is a scale-free measure of how heavy the third-order absolute deviations are, not a measure of asymmetry, and not skewness, as the opening of this section noted. It cannot be small merely because a distribution is symmetric: the standard normal itself has $\rho/\sigma^3 = 2\sqrt{2/\pi}\approx 1.60$, and a symmetric heavy-tailed parent has a larger one still. What makes Bernoulli(0.1) converge slowly is that its standardized absolute third moment is large, which here happens to come with marked asymmetry, but the two need not travel together.

We estimate the left-hand side by the Kolmogorov–Smirnov distance between the empirical CDF of $Z_I$ and $\Phi$, as a function of $I$, and confirm the $I^{-1/2}$ slope (parent = Exponential(1)).

In [6]:
# Berry-Esseen bounds the Kolmogorov distance  sup_x |P(Z_I <= x) - Phi(x)|  by
# C * rho / (sigma**3 * sqrt(I)),  with rho = E|X - mu|**3 the third absolute moment.
# We estimate that sup by the Kolmogorov-Smirnov (KS) distance below, then check that
# it decays at the predicted I^(-1/2) rate (a straight line of slope -1/2 on log-log axes).

def ks_distance(Z_r):
    """Two-sided Kolmogorov distance  sup_x |F_emp(x) - Phi(x)|.

    The empirical CDF is a step function, so at each order statistic z_(r) the gap has to be
    measured on BOTH sides of the jump: r/R - Phi(z_(r)) just after it, and Phi(z_(r)) -
    (r-1)/R just before it. Taking only the first understates the supremum.
    """
    Z_sorted_r = np.sort(Z_r)
    R = len(Z_sorted_r)
    F_th_r = stats.norm.cdf(Z_sorted_r)
    d_plus  = np.max(np.arange(1, R + 1) / R - F_th_r)      # above the step
    d_minus = np.max(F_th_r - np.arange(0, R) / R)          # below the step
    return max(d_plus, d_minus)

# Cross-check the implementation against scipy's two-sided one-sample KS statistic.
_z_check = rng.standard_normal(4_000)
assert abs(ks_distance(_z_check)
           - stats.kstest(_z_check, 'norm').statistic) < 1e-12, 'KS distance mismatch'
print('ks_distance agrees with scipy.stats.kstest to machine precision')

I_s = np.array([10, 30, 100, 300, 1000, 3000, 10_000])   # grid of sample sizes, s in [S]
R = 5_000
sampler = lambda size: rng.exponential(1.0, size)
mu, sigma = 1.0, 1.0

ks_s = np.empty(len(I_s))
for s, I in enumerate(I_s):
    Z_r = clt_simulation(sampler, mu, sigma, I=I, R=R)
    ks_s[s] = ks_distance(Z_r)
ks_distance agrees with scipy.stats.kstest to machine precision
In [7]:
fig, ax = plt.subplots(figsize=(7, 4.2))
ax.loglog(I_s, ks_s, 'o-', label=r'KS distance to $\mathcal{N}(0,1)$')
ax.loglog(I_s, ks_s[0] * np.sqrt(I_s[0] / I_s), 'k--', label=r'reference $I^{-1/2}$')
ax.set_xlabel('I')
ax.set_ylabel('KS distance')
ax.set_title('Berry–Esseen rate: parent = Exponential(1)')
ax.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image

The empirical decay matches the theoretical $I^{-1/2}$ rate up to a constant. (On a log-log plot, the slope is $-1/2$.)

2. The Continuous Mapping Theorem¶


Theorem (CMT). Let $g:\mathbb{R}^k\to\mathbb{R}^\ell$ be a function continuous on a set $C$ with $\mathbb{P}(X\in C)=1$. Then:

  • if $X_n\xrightarrow{a.s.}X$, then $g(X_n)\xrightarrow{a.s.}g(X)$;
  • if $X_n\xrightarrow{p}X$, then $g(X_n)\xrightarrow{p}g(X)$;
  • if $X_n\xrightarrow{d}X$, then $g(X_n)\xrightarrow{d}g(X)$.

The CMT lets us propagate convergence statements through smooth functions without re-doing the work. Combined with the LLN, it yields many consistency results.

2.1 Application: consistency of the sample variance¶

The sample variance $S_I^2=\frac{1}{I}\sum_{i\in[I]} (X_i-\bar X_I)^2$ admits the algebraic identity $$ S_I^2 = \frac{1}{I}\sum_{i\in[I]} X_i^2 \;-\; \bar X_I^{\,2}. $$ By the LLN applied to $X_i$ and to $X_i^2$, the two sample averages converge in probability to $\mathbb{E}[X_1]$ and $\mathbb{E}[X_1^2]$ respectively. By the CMT applied to the continuous map $(a,b)\mapsto b - a^2$, $$ S_I^2 \xrightarrow{p} \mathbb{E}[X_1^2] - \mathbb{E}[X_1]^2 = \sigma^2. $$

(We use the $\tfrac{1}{I}$ divisor here for the clean CMT argument; the studentized mean and confidence interval in §3–§4 use the unbiased $\tfrac{1}{I-1}$ version, for which the exact finite-sample distribution is $t_{I-1}$ under normality. The two are asymptotically equivalent.) We verify this on a Lognormal sample, whose true variance equals $(e-1)e\approx 4.6708$.

In [8]:
I_s = np.unique(np.round(np.logspace(1, 4, 30)).astype(int))   # grid of sample sizes, s in [S]
R = 5
sigma2_true = (np.exp(1) - 1) * np.exp(1)
s2_r_s = np.empty((R, len(I_s)))
for r in range(R):
    x_i = rng.lognormal(0.0, 1.0, size=I_s.max())
    s2_r_s[r] = np.array([x_i[:I].var(ddof=0) for I in I_s])
In [9]:
fig, ax = plt.subplots(figsize=(8, 4.2))
for r in range(R):
    ax.plot(I_s, s2_r_s[r], lw=0.9, alpha=0.85)
ax.axhline(sigma2_true, color='k', ls='--', label=fr'$\sigma^2 = {sigma2_true:.4f}$')
ax.set_xscale('log')
ax.set_xlabel('I (log scale)')
ax.set_ylabel(r'$S_I^2$')
ax.set_title('Sample variance of Lognormal(0,1) draws')
ax.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image

3. Slutsky's theorem¶


Theorem (Slutsky). If $X_n\xrightarrow{d}X$ and $Y_n\xrightarrow{p}c$ for a constant $c$, then:

  • $X_n + Y_n \xrightarrow{d} X + c$,
  • $X_n\, Y_n \xrightarrow{d} c\, X$,
  • $X_n / Y_n \xrightarrow{d} X / c$ (provided $c\neq 0$).

Slutsky's theorem is the standard tool that converts asymptotic-normality statements into usable inference. The pattern is the following: a properly studentized statistic typically splits into a piece that satisfies a CLT (so converges in distribution to a Gaussian) and a piece that converges in probability to a constant. Slutsky tells us the joint object inherits the CLT.

3.1 The studentized sample mean¶

The classical application is the $t$-statistic $$ T_I = \frac{\sqrt{I}\,(\bar X_I - \mu)}{S_I}. $$ Decompose $T_I = (\sqrt{I}\,(\bar X_I-\mu)/\sigma)\cdot(\sigma/S_I)$. The first factor satisfies the CLT (converges in distribution to $\mathcal{N}(0,1)$); the second factor converges in probability to $1$ by the LLN combined with the CMT (applied to $u\mapsto\sigma/\sqrt{u}$, which is continuous at $u=\sigma^2>0$). By Slutsky's theorem, $$ T_I \xrightarrow{d} \mathcal{N}(0,1). $$

3.2 Simulation¶

We compute $T_I$ across $M$ Monte Carlo replications and overlay its empirical CDF against $\mathcal{N}(0,1)$ and the $t_{I-1}$ distribution. One caveat on that second reference curve: $T_I\sim t_{I-1}$ exactly only when the parent is normal, and the sampler here is Exponential(1). So $t_{I-1}$ is drawn as a useful comparison, not as the exact finite-sample law of the simulated statistic. Already at $I=20$ the three curves are nearly indistinguishable, with the $t$ reference slightly heavier-tailed.

In [10]:
def t_simulation(sampler, mu, I=20, R=20_000):
    X_r_i = sampler(size=(R, I))
    mean_r = X_r_i.mean(axis=1)
    sd_r = X_r_i.std(axis=1, ddof=1)
    T_r = np.sqrt(I) * (mean_r - mu) / sd_r
    return T_r

I = 20
R = 20_000
sampler = lambda size: rng.exponential(1.0, size)
T_r = t_simulation(sampler, mu=1.0, I=I, R=R)

# Empirical CDF vs N(0,1) and t_{I-1}
T_sorted_r = np.sort(T_r)
F_emp_r = np.arange(1, R+1) / R
z_g = np.linspace(-5, 5, 400)

# Q-Q plot vs N(0,1)
u_q = np.linspace(0.005, 0.995, 200)      # quantile levels, q in [Q]
qemp_q = np.quantile(T_r, u_q)
qth_q = stats.norm.ppf(u_q)
In [11]:
fig, axes = plt.subplots(1, 2, figsize=(12, 4.2))

axes[0].plot(T_sorted_r, F_emp_r, lw=1.4, label=f'empirical CDF, I={I}')
axes[0].plot(z_g, stats.norm.cdf(z_g), 'k--', lw=1.0, label=r'$\mathcal{N}(0,1)$')
axes[0].plot(z_g, stats.t.cdf(z_g, df=I-1), 'r:', lw=1.2, label=fr'$t_{{{I-1}}}$')
axes[0].set_xlim(-5, 5)
axes[0].set_xlabel(r'$T_I$')
axes[0].set_ylabel('CDF')
axes[0].legend(loc='lower right')
axes[0].set_title('CDF of the studentized mean')

axes[1].plot(qth_q, qemp_q, 'o', ms=2.5)
axes[1].plot([-3, 3], [-3, 3], 'k--', lw=1.0)
axes[1].set_xlabel(r'theoretical $\mathcal{N}(0,1)$ quantiles')
axes[1].set_ylabel(r'empirical $T_I$ quantiles')
axes[1].set_title(fr'Q–Q plot of $T_I$ vs $\mathcal{{N}}(0,1)$, I = {I}')
plt.tight_layout()
plt.show()
No description has been provided for this image

Even at $I=20$, the empirical CDF of the studentized mean tracks both the standard normal and the $t_{I-1}$ closely. The Q–Q plot reveals the residual tail behavior: the empirical quantiles slightly exceed the Gaussian ones in the extremes, consistent with the heavier tails of the $t_{I-1}$, which is the exact finite-sample distribution of $T_I$ when the parent is normal.

4. Synthesis: an asymptotic confidence interval for the mean log-wage¶

We close the lecture by combining the four tools, LLN, CLT, CMT, Slutsky, to produce an asymptotic $1-\alpha$ confidence interval for $\mu = \mathbb{E}[\log\text{wage}]$ in the Mroz population. The construction reads: $$ \sqrt{I}\,(\bar X_I - \mu) \xrightarrow{d} \mathcal{N}(0,\sigma^2) \qquad\text{(CLT)}, $$ $$ S_I \xrightarrow{p} \sigma \qquad\text{(LLN + CMT)}, $$ $$ \frac{\sqrt{I}\,(\bar X_I-\mu)}{S_I}\xrightarrow{d}\mathcal{N}(0,1) \qquad\text{(Slutsky)}. $$ Inverting the last statement, $$ \mathrm{CI}_{1-\alpha} = \Bigl[\bar X_I - z_{1-\alpha/2}\,S_I/\sqrt{I},\;\;\bar X_I + z_{1-\alpha/2}\,S_I/\sqrt{I}\Bigr] $$ covers $\mu$ with probability tending to $1-\alpha$ as $I\to\infty$. We compute it on the Mroz working-women sample and benchmark it against the exact-Gaussian (i.e., $t_{I-1}$) interval one would obtain under a normality assumption.

In [12]:
x_i = mroz_w['lwage'].values
I = len(x_i)
xbar = x_i.mean()
s = x_i.std(ddof=1)
se = s / np.sqrt(I)

alpha = 0.05
z = stats.norm.ppf(1 - alpha/2)
t_crit = stats.t.ppf(1 - alpha/2, df=I-1)

ci_asy = (xbar - z*se, xbar + z*se)
ci_exact = (xbar - t_crit*se, xbar + t_crit*se)

print(f'  I          = {I}')
print(f'  mean lwage = {xbar:.4f}')
print(f'  s.e.       = {se:.4f}')
print(f'  asymptotic 95% CI (CLT+Slutsky) = [{ci_asy[0]:.4f}, {ci_asy[1]:.4f}]')
print(f'  exact      95% CI (t_{I-1})       = [{ci_exact[0]:.4f}, {ci_exact[1]:.4f}]')
  I          = 428
  mean lwage = 1.1902
  s.e.       = 0.0350
  asymptotic 95% CI (CLT+Slutsky) = [1.1217, 1.2587]
  exact      95% CI (t_427)       = [1.1215, 1.2589]

The two intervals differ at the fourth decimal place, at $I=428$ the gap between $z_{0.975}\approx 1.960$ and $t_{427,0.975}\approx 1.966$ is numerically negligible. This is the practical implication of asymptotic theory: once $I$ is moderately large, the choice between the $t$ and normal critical values is irrelevant next to the width contributed by the estimated standard error itself, $S_I/\sqrt{I}$. That quantity is the sampling standard error of $\bar X_I$, the irreducible uncertainty from having $I$ observations rather than the whole population. It is not Monte Carlo error, which would be the separate numerical noise from running only $M$ simulation replications, and which we could shrink at will by raising $M$.

Looking ahead¶

Lectures 1 and 2 together assembled the asymptotic toolkit, LLN, CLT, CMT, Slutsky, that the rest of the course deploys:

  • In Lecture 3 we set up the OLS estimator and develop its finite-sample theory, then apply Slutsky directly to obtain consistency.

  • The following lecture derives the asymptotic normality of $\hat\beta_{\text{OLS}}$ and the heteroskedasticity-robust variance: the same CLT–CMT–Slutsky sandwich seen here, applied componentwise.

  • Later (MLE, GMM, discrete choice) the same template recurs, with the sample average replaced by a sample score, a sample moment, or a sample log-likelihood.

Each subsequent estimator we encounter is, in this sense, a corollary of Lectures 1–2.