Probability basics
ΒΆ

Alfred Galichon (NYU)
ΒΆ

'math+econ+code' masterclass series: econometrics
ΒΆ

Conditional expectations, modes of convergence, and the LLN
ΒΆ

Β© 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ΒΆ

  • Recall the basic vocabulary used throughout econometrics: probability spaces, random variables, conditional expectations, and the Law of Iterated Expectations (LIE).

  • Verify LIE and the variance decomposition formula on a real dataset, and connect them to the Conditional Expectation Function (CEF): the central object of regression analysis.

  • Distinguish the four standard modes of convergence for sequences of random variables: almost sure, in probability, in $L^p$, and in distribution; remember the hierarchy among them.

  • Use the Law of Large Numbers (LLN) to derive the asymptotic behavior of sample averages, and visualize the conclusion through simulation.

The Central Limit Theorem and its companions (CMT, Slutsky), together with a first confidence interval, are taken up in Lecture 2.

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: from samples to populationsΒΆ

  • Almost every estimator in econometrics has the form of a sample average: possibly composed with a smooth function, possibly applied to a transformed dataset. OLS, IV, MLE, and GMM all fall into this template after a suitable reformulation.

  • As a consequence, the entire toolkit of asymptotic statistics, LLN, CLT, CMT, Slutsky, translates almost mechanically into statements about the behavior of econometric estimators. Most of the work later in the course will consist of recognizing the right sample-average representation and applying these tools.

  • This first lecture is therefore foundational rather than applied. We adopt a simulation-first approach: every theorem will be illustrated by Monte Carlo experiments where the data-generating process is known, so that the asymptotic behavior is a conclusion that one can check directly in a plot.

  • For one important computation, the law of iterated expectations, we work directly with a real dataset, namely the Mroz (1987) sample of married women's labor supply. This dataset will reappear throughout the course.

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. Conditional expectations and the Law of Iterated ExpectationsΒΆ

1.1 The conditional expectationΒΆ

Split the population into groups according to the value of a variable $X$, and average $Y$ within each group:

$$ \mathbb{E}[Y \mid X = x] \;=\; \text{the average of } Y \text{ over just those cases with } X = x . $$

Doing this for every value $x$ produces a function of $x$, $$ m(x) \;:=\; \mathbb{E}[Y \mid X = x], $$ called the Conditional Expectation Function (CEF): the central object of regression analysis. Writing $\mathbb{E}[Y\mid X] := m(X)$ turns it into a random variable: its value is whichever group average corresponds to the $X$ you happened to draw.

We shall use the following two properties throughout this section:

  • $\mathbb{E}[Y\mid X]$ is constant within each group: it carries only the information contained in $X$;
  • it is the best predictor of $Y$ given $X$: among all functions $g$, the choice $g=m$ minimizes the mean squared error $\mathbb{E}\bigl[(Y-g(X))^2\bigr]$.

For a discrete $X$, the group average is literally $$ \mathbb{E}[Y\mid X=x] \;=\; \sum_{y} y\,\mathbb{P}(Y=y \mid X=x), $$ and when $X$ is continuous the sums become integrals. (There is a general measure-theoretic definition that covers both at once, and allows conditioning on richer information than a single variable. We will not need it in this course.)

The toy example below, a single fair die, makes the idea concrete.

InΒ [4]:
# A finite example: one roll of a fair die.  Outcomes omega_i, i in [I] := {1,...,I},
# with I = 6, each with probability 1/I.
I = 6
omega_i = np.arange(1, I + 1)
p_i     = np.full(I, 1 / I)
Y_i     = omega_i ** 2                    # the random variable  Y(omega) = omega^2

# Condition on X = parity.  Two groups: odd {1,3,5} and even {2,4,6}.
is_even_i = (omega_i % 2 == 0)

# E[Y | X] is constant on each group, equal to the average of Y within that group.
condexp_i = np.empty(I)
for group_i in (~is_even_i, is_even_i):
    condexp_i[group_i] = np.average(Y_i[group_i], weights=p_i[group_i])

print("omega          =", omega_i)
print("Y = omega^2    =", Y_i)
print("E[Y | parity]  =", condexp_i, "  <- constant within each group")
print()
print(f"  E[Y | X=odd ] = {condexp_i[~is_even_i][0]:.4f}   (= 35/3)")
print(f"  E[Y | X=even] = {condexp_i[ is_even_i][0]:.4f}   (= 56/3)")
print()
print(f"LIE:  E[ E[Y|X] ] = {np.dot(p_i, condexp_i):.6f}")
print(f"      E[Y]        = {np.dot(p_i, Y_i):.6f}   (= 91/6)")
omega          = [1 2 3 4 5 6]
Y = omega^2    = [ 1  4  9 16 25 36]
E[Y | parity]  = [11.66666667 18.66666667 11.66666667 18.66666667 11.66666667 18.66666667]   <- constant within each group

  E[Y | X=odd ] = 11.6667   (= 35/3)
  E[Y | X=even] = 18.6667   (= 56/3)

LIE:  E[ E[Y|X] ] = 15.166667
      E[Y]        = 15.166667   (= 91/6)

Each value of E[Y | parity] is a group average, and averaging those groups with their probabilities recovers $\mathbb{E}[Y]=91/6$: the Law of Iterated Expectations, which we now state in general.

1.2 Law of Iterated ExpectationsΒΆ


Theorem (LIE). For random variables $X,Y$ with $\mathbb{E}\lvert Y\rvert<\infty$, $$ \mathbb{E}\bigl[\mathbb{E}[Y\mid X]\bigr] = \mathbb{E}[Y]. $$ In words: the average of the group averages, each weighted by how likely that group is, is the overall average.


Why it is true. Sort everybody into groups by the value of $X$. Adding up $Y$ group by group, and then across groups, is the same as adding up over everybody: $$ \mathbb{E}[Y] \;=\; \sum_x \mathbb{P}(X=x)\,\underbrace{\mathbb{E}[Y\mid X=x]}_{m(x)} \;=\; \mathbb{E}\bigl[m(X)\bigr] \;=\; \mathbb{E}\bigl[\mathbb{E}[Y\mid X]\bigr]. \qquad \square $$ For continuous $X$ the sum becomes an integral and the argument is unchanged.

A useful extension is the tower property: conditioning on less information averages the finer group means into the coarser ones: for instance $\mathbb{E}\bigl[\mathbb{E}[Y\mid X_1,X_2]\mid X_1\bigr]=\mathbb{E}[Y\mid X_1]$.

1.3 Variance decompositionΒΆ

A second consequence of LIE is the variance decomposition (sometimes called the law of total variance): $$ \operatorname{Var}(Y) = \mathbb{E}\bigl[\operatorname{Var}(Y\mid X)\bigr] + \operatorname{Var}\bigl(\mathbb{E}[Y\mid X]\bigr). $$

The first term is the within-group variance, the residual variation around the CEF, and the second is the between-group variance: the variation of the CEF itself. The ratio of the between-group variance to the total variance is the population $R^2$ of $Y$ on $X$.

1.4 Verification on Mroz dataΒΆ

We bin years of education into discrete categories, treat the cell means as estimates of the CEF $\mathbb{E}[\log\text{wage}\mid\text{educ bucket}]$, and verify both formulas numerically. We use sample analogs throughout: the population formulas hold exactly when expectations are taken with respect to the empirical measure.

InΒ [5]:
# Bucket education into 4 categories
edges = [0, 11, 12, 15, 17]
labels = ['<HS', 'HS', 'Some college', 'College+']
mroz_w['educ_bucket'] = pd.cut(mroz_w['educ'], bins=edges, labels=labels, right=True)

# Sample CEF: cell means of log-wage by education bucket.
# We use ddof=0 (i.e. dividing by n_x rather than n_x-1) so that
# the variance decomposition holds exactly with respect to the empirical measure.
aggregated = mroz_w.groupby('educ_bucket', observed=True)['lwage'].agg(
    **{
        'E[lwage|x]':  'mean',
        'Var[lwage|x]': lambda s: s.var(ddof=0),
        'n_x':         'count',
    }
)
print(aggregated.round(4))
              E[lwage|x]  Var[lwage|x]  n_x
educ_bucket                                
<HS               0.8765        0.4400   72
HS                1.1273        0.4153  212
Some college      1.1585        0.6430   66
College+          1.6774        0.4443   78
InΒ [6]:
aggregated.head()
Out[6]:
E[lwage|x] Var[lwage|x] n_x
educ_bucket
<HS 0.876487 0.439997 72
HS 1.127295 0.415305 212
Some college 1.158493 0.643023 66
College+ 1.677436 0.444298 78
InΒ [7]:
mroz_w.head()
Out[7]:
lfp hours kids5 kids618 age educ wage repwage hushrs husage ... mtr motheduc fatheduc unem city exper nwifeinc lwage expersq educ_bucket
0 1 1610 1 0 32 12 3.3540 2.65 2708 34 ... 0.7215 12 7 5.0 0 14 10.910060 1.210154 196 HS
1 1 1656 0 2 30 12 1.3889 2.65 2310 30 ... 0.6615 7 7 11.0 1 5 19.499981 0.328512 25 HS
2 1 1980 1 3 35 12 4.5455 4.04 3072 40 ... 0.6915 12 7 5.0 0 15 12.039910 1.514138 225 HS
3 1 456 0 3 34 12 1.0965 3.25 1920 53 ... 0.7815 7 7 5.0 0 6 6.799996 0.092123 36 HS
4 1 1568 1 2 31 14 4.5918 3.60 2000 32 ... 0.6215 12 14 9.5 1 7 20.100058 1.524272 49 Some college

5 rows Γ— 23 columns

InΒ [8]:
# Verify LIE: weighted average of conditional means equals overall mean
N = aggregated['n_x'].sum()
w_b = aggregated['n_x'] / N                       # weight of each education bucket b
E_lwage = (w_b * aggregated['E[lwage|x]']).sum()  # E[E[Y|X]]
E_lwage_direct = mroz_w['lwage'].mean()           # E[Y]

print(f'  E[E[lwage|educ]]  =  {E_lwage:.6f}')
print(f'  E[lwage]          =  {E_lwage_direct:.6f}')
print(f'  difference        =  {E_lwage - E_lwage_direct:.2e}')
  E[E[lwage|educ]]  =  1.190173
  E[lwage]          =  1.190173
  difference        =  0.00e+00
InΒ [9]:
# Verify the variance decomposition
within  = (w_b * aggregated['Var[lwage|x]']).sum()              # E[Var(Y|X)]
between = (w_b * (aggregated['E[lwage|x]'] - E_lwage)**2).sum() # Var(E[Y|X])
total   = mroz_w['lwage'].var(ddof=0)                           # Var(Y)

print(f'  E[Var(lwage|educ)]   (within)   =  {within:.6f}')
print(f'  Var(E[lwage|educ])   (between)  =  {between:.6f}')
print(f'  sum                              =  {within + between:.6f}')
print(f'  Var(lwage)                       =  {total:.6f}')
print(f'  population R^2                   =  {between/total:.4f}')
  E[Var(lwage|educ)]   (within)   =  0.459858
  Var(E[lwage|educ])   (between)  =  0.061935
  sum                              =  0.521793
  Var(lwage)                       =  0.521793
  population R^2                   =  0.1187

The numbers match up to numerical precision, as they must when the expectations are computed with respect to the empirical distribution. About $12\%$ of the variance of log-wages is explained by the education bucket: the rest is residual variation around the CEF. A standard regression of lwage on continuous educ would extract a slightly different $R^2$, since the linear projection is a coarser summary of $\mathbb{E}[Y\mid X]$ than the full CEF; we return to this distinction in Lecture 3.

2. Modes of convergenceΒΆ

Let $(X_n)_{n\geq 1}$ and $X$ be random variables on $(\Omega,\mathcal{F},\mathbb{P})$, with distribution functions $F_n$ and $F$.

  • Almost sure convergence ($X_n\xrightarrow{a.s.}X$):
$$ \mathbb{P}\bigl(\lim_{n\to\infty} X_n = X\bigr) = 1. $$
  • Convergence in probability ($X_n\xrightarrow{p}X$): for every $\varepsilon>0$,
$$ \lim_{n\to\infty} \mathbb{P}\bigl(\lvert X_n - X\rvert > \varepsilon\bigr) = 0. $$
  • Convergence in $L^p$ ($X_n\xrightarrow{L^p}X$, $p\geq 1$):
$$ \lim_{n\to\infty} \mathbb{E}\bigl[\lvert X_n - X\rvert^p\bigr] = 0. $$
  • Convergence in distribution ($X_n\xrightarrow{d}X$): $F_n(x)\to F(x)$ at every continuity point $x$ of $F$.

The hierarchy between these modes is summarized as follows:

$$ X_n\xrightarrow{a.s.}X \;\Longrightarrow\; X_n\xrightarrow{p}X \;\Longrightarrow\; X_n\xrightarrow{d}X, $$

and $$ X_n\xrightarrow{L^p}X \;\Longrightarrow\; X_n\xrightarrow{p}X. $$

None of the reverse implications hold in general. However, two partial converses are useful:

  • if $X_n\xrightarrow{d}c$ for a constant $c$, then $X_n\xrightarrow{p}c$;
  • if $X_n\xrightarrow{p}X$ and $(X_n)$ is uniformly integrable, then $X_n\xrightarrow{L^1}X$.

2.1 A.s. is strictly stronger than in probabilityΒΆ

We illustrate that convergence in probability does not imply almost sure convergence. The classical typewriter sequence on $[0,1]$ provides the textbook counterexample. Let $U\sim\mathrm{Unif}(0,1)$ and define, for $n=2^k+j$ with $0\leq j<2^k$, $$ X_n = \mathbf{1}\bigl\{U\in[j/2^k,(j+1)/2^k]\bigr\}. $$ Then $\mathbb{P}(X_n=1)=2^{-k}\to 0$, so $X_n\xrightarrow{p}0$. However, for every $\omega\in[0,1)$, $X_n(\omega)=1$ infinitely often, hence $X_n(\omega)\not\to 0$. We visualize this below.

InΒ [10]:
def typewriter(u, n):
    # X_n(u) for n = 2^k + j, 0 <= j < 2^k
    n = np.asarray(n)
    k = np.floor(np.log2(np.maximum(n, 1))).astype(int)
    j = n - 2**k
    return ((u >= j/2**k) & (u < (j+1)/2**k)).astype(float)

M = 255
n_m = np.arange(1, M + 1)          # the sequence of n's, indexed by m

# Left: P(X_n = 1) -> 0 (convergence in probability)
p_m = 2.0 ** (-np.floor(np.log2(np.maximum(n_m, 1))).astype(int))

# Right: a single sample path X_n(omega) β€” infinitely many 1's
u = 0.37
X_m = typewriter(u, n_m)
InΒ [11]:
fig, axes = plt.subplots(1, 2, figsize=(12, 4))

axes[0].plot(n_m, p_m, lw=1.2)
axes[0].set_xlabel('n')
axes[0].set_ylabel(r'$\mathbb{P}(X_n = 1)$')
axes[0].set_title(r'Convergence in probability: $\mathbb{P}(X_n=1)\to 0$')
axes[0].set_yscale('log')

axes[1].vlines(n_m, 0, X_m, lw=0.7)
axes[1].set_xlabel('n')
axes[1].set_ylabel(r'$X_n(\omega)$')
axes[1].set_title(r'Sample path at $\omega$ with $U(\omega)=0.37$: not a.s. convergent')
plt.tight_layout()
plt.show()
No description has been provided for this image

On the left, the probability that $X_n=1$ decays geometrically, convergence in probability holds. On the right, a single realization of the sequence keeps hitting $1$ at arbitrarily large $n$, the sequence does not converge almost surely.

3. The Law of Large NumbersΒΆ

3.1 StatementΒΆ


Theorem (Khintchine's Weak LLN). If $(X_i)_{i\geq 1}$ are i.i.d. with $\mathbb{E}\lvert X_1\rvert <\infty$ and mean $\mu$, then $$ \bar X_I := \frac{1}{I}\sum_{i\in[I]} X_i \xrightarrow{p} \mu, \qquad [I]:=\{1,\dots,I\}. $$


Theorem (Kolmogorov's Strong LLN). Under the same hypotheses, $\bar X_I\xrightarrow{a.s.}\mu$.


Proof of the WLLN under finite variance. Suppose in addition $\sigma^2:=\operatorname{Var}(X_1)<\infty$. Then $\operatorname{Var}(\bar X_I)=\sigma^2/I$, and Chebyshev's inequality yields $$ \mathbb{P}\bigl(\lvert \bar X_I-\mu\rvert > \varepsilon\bigr) \leq \frac{\sigma^2}{I\varepsilon^2}\to 0. \qquad\square $$

The full WLLN (without the finite variance assumption) and the SLLN require more work; see [vdV, ch. 1] or [H, ch. 5–6].

3.2 SimulationΒΆ

We draw i.i.d. samples from a few distributions with finite mean, plot the running sample mean as a function of $I$, and overlay the true mean.

InΒ [12]:
def running_mean(x_i):
    return np.cumsum(x_i) / np.arange(1, len(x_i) + 1)

I = 10_000
R = 5
specs = {
    'Normal(0,1)':       (lambda size: rng.standard_normal(size), 0.0),
    'Exponential(1)':    (lambda size: rng.exponential(1.0, size), 1.0),
    'Bernoulli(0.3)':    (lambda size: (rng.random(size) < 0.3).astype(float), 0.3),
    'Pareto(Ξ±=2.5, x_m=1)': (lambda size: (rng.pareto(2.5, size) + 1) * 1.0, 2.5/(2.5-1)),
}

S = len(specs)
running_mean_s_r_i = np.empty((S, R, I))
for s, (_, (sampler, _)) in enumerate(specs.items()):
    for r in range(R):
        x_i = sampler(I)
        running_mean_s_r_i[s, r] = running_mean(x_i)
InΒ [13]:
fig, axes = plt.subplots(2, 2, figsize=(11, 6.5), sharex=True)
for s, (ax, (name, (_, mu_true))) in enumerate(zip(axes.flat, specs.items())):
    for r in range(R):
        ax.plot(running_mean_s_r_i[s, r], lw=0.8, alpha=0.85)
    ax.axhline(mu_true, color='k', ls='--', lw=1.0, label=fr'$\mu = {mu_true:.3f}$')
    ax.set_xscale('log')
    ax.set_title(name)
    ax.set_ylabel(r'$\bar X_I$')
    ax.legend(loc='upper right', fontsize=9)
axes[1, 0].set_xlabel('I (log scale)')
axes[1, 1].set_xlabel('I (log scale)')
plt.tight_layout()
plt.show()
No description has been provided for this image

Each panel shows five independent realizations of $\bar X_I$ for $I$ ranging from $1$ to $10\,000$, against a logarithmic $x$-axis. The convergence is visible in every panel, although the rate is conspicuously slower for the heavy-tailed Pareto distribution (which has finite mean only because $\alpha>1$).

3.3 A counterexample: the Cauchy distributionΒΆ

The LLN can fail when the integrability assumption fails. The Cauchy distribution has no mean, $\mathbb{E}\lvert X_1\rvert=\infty$, and the sample mean of i.i.d. Cauchy draws is itself Cauchy-distributed (this is a striking property of the Cauchy: $\bar X_I\stackrel{d}{=} X_1$). Hence $\bar X_I$ does not converge to anything.

InΒ [14]:
cauchy_running_mean_r_i = np.empty((R, I))
for r in range(R):
    x_i = rng.standard_cauchy(I)
    cauchy_running_mean_r_i[r] = running_mean(x_i)
InΒ [15]:
fig, ax = plt.subplots(figsize=(8, 4))
for r in range(R):
    ax.plot(cauchy_running_mean_r_i[r], lw=0.8, alpha=0.85)
ax.axhline(0, color='k', ls='--', lw=1.0, label='median = 0')
ax.set_xscale('log')
ax.set_xlabel('I (log scale)')
ax.set_ylabel(r'$\bar X_I$')
ax.set_title('Sample mean of i.i.d. Cauchy: no convergence')
ax.legend()
plt.tight_layout()
plt.show()
No description has been provided for this image

The running sample means jump erratically and never settle: a direct consequence of the absence of a mean. The dashed line indicates the median, which is well-defined and toward which the sample median (not the mean) does converge.

Looking aheadΒΆ

This lecture has introduced the first half of the asymptotic toolkit: the conditional expectation function and the Law of Iterated Expectations (the language of regression), the modes of convergence, and the Law of Large Numbers (consistency of sample averages).

Lecture 2 completes the toolkit with the Central Limit Theorem, the Continuous Mapping Theorem, and Slutsky's theorem, and combines all four into an asymptotic confidence interval for the mean log-wage. From Lecture 3 onward these tools are deployed on the OLS estimator and every estimator that follows.