Skip to content

Commit b0d5f76

Browse files
jstacclaudemmcky
authored
[stationary_densities] Fix typos and align with style manual (#331)
* [stationary_densities] Fix typos and minor code issues - Fix "for all s" -> "for all x" in state space remark - Correct off-by-one comment on density dates (1,...,T) - Remove stray trailing comma in boxplot data display - "discrete-time" -> "discrete time" (noun usage) - Add missing period after Markov operator definition - Initialize X[0] in exercise 1 solution (was uninitialized np.empty) - Boxplot titles: label initial condition as X_0, not t - Comments: B ~ N(0, a_σ**2) since a_σ is the std dev Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [stationary_densities] Align lecture with QuantEcon style manual - Links: use intersphinx {doc} links for finite_markov references, normalize outdated python-intro.quantecon.org domain, auto-title link for arma - Citation: use {cite:t} for in-sentence Hopenhayn-Rogerson reference - Definitions: bold (not italic) for stochastic kernel, Markov operator, look-ahead, stationary, global stability, ergodicity - Math: square brackets for expectation, \mathrm{LN} for lognormal, "CDFs" capitalization - Figures: replace ax.set_title with mystnb caption on the main example, caption the static stability figure, drop unneeded figsize settings, format ex-3 panel titles to one decimal - RNG: migrate to np.random.default_rng Generator API; seed scipy .rvs calls via random_state for reproducibility Verified by executing the full lecture via jupytext --to py and inspecting all five generated figures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * FIX: disambiguate arma cross-reference to fix build The auto-title link `[](arma)` was ambiguous: MyST found both a doc target (Covariance Stationary Processes) and an equation labelled `arma`, raising myst.xref_ambiguous. With warnings treated as errors the book build failed. Use the explicit `{doc}` role to resolve to the document while keeping the auto-generated title. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Matt McKay <mmcky@users.noreply.github.com>
1 parent f2447ab commit b0d5f76

1 file changed

Lines changed: 50 additions & 38 deletions

File tree

lectures/stationary_densities.md

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,20 @@ tags: [hide-output]
3434

3535
## Overview
3636

37-
In a [previous lecture](https://python-intro.quantecon.org/finite_markov.html), we learned about finite Markov chains, a relatively elementary class of stochastic dynamic models.
37+
In {doc}`intermediate:finite_markov`, we learned about finite Markov chains, a relatively elementary class of stochastic dynamic models.
3838

3939
The present lecture extends this analysis to continuous (i.e., uncountable) state Markov chains.
4040

4141
Most stochastic dynamic models studied by economists either fit directly into this class or can be represented as continuous state Markov chains after minor modifications.
4242

4343
In this lecture, our focus will be on continuous Markov models that
4444

45-
* evolve in discrete-time
45+
* evolve in discrete time
4646
* are often nonlinear
4747

4848
The fact that we accommodate nonlinear models here is significant, because
4949
linear stochastic models have their own highly developed toolset, as we'll
50-
see {doc}`later on <arma>`.
50+
see later in {doc}`arma`.
5151

5252
The question that interests us most is: Given a particular stochastic dynamic
5353
model, how will the state of the system evolve over time?
@@ -96,7 +96,7 @@ Once we've built some intuition we'll cover the general case.
9696

9797
### Definitions and basic properties
9898

99-
In our [lecture on finite Markov chains](https://python-intro.quantecon.org/finite_markov.html), we studied discrete-time Markov chains that evolve on a finite state space $S$.
99+
In our lecture {doc}`intermediate:finite_markov`, we studied discrete-time Markov chains that evolve on a finite state space $S$.
100100

101101
In this setting, the dynamics of the model are described by a stochastic matrix --- a nonnegative square matrix $P = P[i, j]$ such that each row $P[i, \cdot]$ sums to one.
102102

@@ -127,7 +127,7 @@ The family of discrete distributions $P[i, \cdot]$ will be replaced by a family
127127

128128
Analogous to the finite state case, $p(x, \cdot)$ is to be understood as the distribution (density) of $X_{t+1}$ given $X_t = x$.
129129

130-
More formally, a *stochastic kernel on* $S$ is a function $p \colon S \times S \to \mathbb R$ with the property that
130+
More formally, a **stochastic kernel on** $S$ is a function $p \colon S \times S \to \mathbb R$ with the property that
131131

132132
1. $p(x, y) \geq 0$ for all $x, y \in S$
133133
1. $\int p(x, y) dy = 1$ for all $x \in S$
@@ -274,7 +274,7 @@ p(x, y)
274274
where $\phi$ is the density of $A_{t+1}$.
275275

276276
(Regarding the state space $S$ for this model, a natural choice is $(0, \infty)$ --- in which case
277-
$\sigma(x) = s f(x)$ is strictly positive for all $s$ as required)
277+
$\sigma(x) = s f(x)$ is strictly positive for all $x$ as required)
278278

279279
### Distribution dynamics
280280

@@ -322,7 +322,7 @@ defined by
322322
(\psi P)(y) = \int p(x,y) \psi(x) dx
323323
```
324324

325-
This operator is usually called the *Markov operator* corresponding to $p$
325+
This operator is usually called the **Markov operator** corresponding to $p$.
326326

327327
```{note}
328328
Unlike most operators, we write $P$ to the right of its argument,
@@ -368,7 +368,7 @@ $y$.
368368

369369
Another possibility is to discretize the model, but this introduces errors of unknown size.
370370

371-
A nicer alternative in the present setting is to combine simulation with an elegant estimator called the *look-ahead* estimator.
371+
A nicer alternative in the present setting is to combine simulation with an elegant estimator called the **look-ahead** estimator.
372372

373373
Let's go over the ideas with reference to the growth model {ref}`discussed above <solow_swan>`, the dynamics of which we repeat here for convenience:
374374

@@ -412,12 +412,12 @@ where $p$ is the growth model stochastic kernel in {eq}`statd_sssk`.
412412

413413
What is the justification for this slightly surprising estimator?
414414

415-
The idea is that, by the strong [law of large numbers](https://python-intro.quantecon.org/lln_clt.html#lln-ksl),
415+
The idea is that, by the strong [law of large numbers](https://python.quantecon.org/lln_clt.html#lln-ksl),
416416

417417
$$
418418
\frac{1}{n} \sum_{i=1}^n p(k_{t-1}^i, y)
419419
\to
420-
\mathbb E p(k_{t-1}^i, y)
420+
\mathbb E \left[ p(k_{t-1}^i, y) \right]
421421
= \int p(x, y) \psi_{t-1}(x) \, dx
422422
= \psi_t(y)
423423
$$
@@ -462,13 +462,20 @@ The following code is an example of usage for the stochastic growth model {ref}`
462462

463463
(stoch_growth)=
464464
```{code-cell} python3
465+
---
466+
mystnb:
467+
figure:
468+
caption: Density of $k_1$ (lighter) to $k_T$ (darker)
469+
name: fig-statd-density-sequence
470+
---
465471
# == Define parameters == #
466472
s = 0.2
467473
δ = 0.1
468-
a_σ = 0.4 # A = exp(B) where B ~ N(0, a_σ)
474+
a_σ = 0.4 # A = exp(B) where B ~ N(0, a_σ**2)
469475
α = 0.4 # We set f(k) = k**α
470476
ψ_0 = beta(5, 5, scale=0.5) # Initial distribution
471477
ϕ = lognorm(a_σ)
478+
rng = np.random.default_rng(1234)
472479
473480
474481
def p(x, y):
@@ -480,12 +487,12 @@ def p(x, y):
480487
return ϕ.pdf((y - (1 - δ) * x) / d) / d
481488
482489
n = 10000 # Number of observations at each date t
483-
T = 30 # Compute density of k_t at 1,...,T+1
490+
T = 30 # Compute density of k_t at 1,...,T
484491
485492
# == Generate matrix s.t. t-th column is n observations of k_t == #
486493
k = np.empty((n, T))
487-
A = ϕ.rvs((n, T))
488-
k[:, 0] = ψ_0.rvs(n) # Draw first column from initial distribution
494+
A = ϕ.rvs((n, T), random_state=rng)
495+
k[:, 0] = ψ_0.rvs(n, random_state=rng) # Draw first column from initial distribution
489496
for t in range(T-1):
490497
k[:, t+1] = s * A[:, t] * k[:, t]**α + (1 - δ) * k[:, t]
491498
@@ -500,7 +507,6 @@ greys.reverse()
500507
for ψ, g in zip(laes, greys):
501508
ax.plot(ygrid, ψ(ygrid), color=g, lw=2, alpha=0.6)
502509
ax.set_xlabel('capital')
503-
ax.set_title(f'Density of $k_1$ (lighter) to $k_T$ (darker) for $T={T}$')
504510
plt.show()
505511
```
506512

@@ -531,7 +537,7 @@ We can, however, construct a fairly general theory using distribution functions.
531537

532538
### Example and definitions
533539

534-
To illustrate the issues, recall that Hopenhayn and Rogerson {cite}`HopenhaynRogerson1993` study a model of firm dynamics where individual firm productivity follows the exogenous process
540+
To illustrate the issues, recall that {cite:t}`HopenhaynRogerson1993` study a model of firm dynamics where individual firm productivity follows the exogenous process
535541

536542
$$
537543
X_{t+1} = a + \rho X_t + \xi_{t+1},
@@ -557,7 +563,7 @@ puts positive probability mass on 0 and 1.
557563

558564
Hence it cannot be represented as a density.
559565

560-
What we can do instead is use cumulative distribution functions (cdfs).
566+
What we can do instead is use cumulative distribution functions (CDFs).
561567

562568
To this end, set
563569

@@ -566,7 +572,7 @@ G(x, y) := \mathbb P \{ h(a + \rho x + \xi_{t+1}) \leq y \}
566572
\qquad (0 \leq x, y \leq 1)
567573
$$
568574

569-
This family of cdfs $G(x, \cdot)$ plays a role analogous to the stochastic kernel in the density case.
575+
This family of CDFs $G(x, \cdot)$ plays a role analogous to the stochastic kernel in the density case.
570576

571577
The distribution dynamics in {eq}`statd_fdd` are then replaced by
572578

@@ -576,13 +582,13 @@ The distribution dynamics in {eq}`statd_fdd` are then replaced by
576582
F_{t+1}(y) = \int G(x,y) F_t(dx)
577583
```
578584

579-
Here $F_t$ and $F_{t+1}$ are cdfs representing the distribution of the current state and next period state.
585+
Here $F_t$ and $F_{t+1}$ are CDFs representing the distribution of the current state and next period state.
580586

581587
The intuition behind {eq}`statd_fddc` is essentially the same as for {eq}`statd_fdd`.
582588

583589
### Computation
584590

585-
If you wish to compute these cdfs, you cannot use the look-ahead estimator as before.
591+
If you wish to compute these CDFs, you cannot use the look-ahead estimator as before.
586592

587593
Indeed, you should not use any density estimator, since the objects you are
588594
estimating/computing are not densities.
@@ -591,7 +597,7 @@ One good option is simulation as before, combined with the [empirical distributi
591597

592598
## Stability
593599

594-
In our [lecture](https://python-intro.quantecon.org/finite_markov.html) on finite Markov chains, we also studied stationarity, stability and ergodicity.
600+
In our lecture {doc}`intermediate:finite_markov`, we also studied stationarity, stability and ergodicity.
595601

596602
Here we will cover the same topics for the continuous case.
597603

@@ -603,7 +609,7 @@ The general case is relatively similar --- references are given below.
603609

604610
Analogous to [the finite case](https://python.quantecon.org/finite_markov.html#stationary-distributions), given a stochastic kernel $p$ and corresponding Markov operator as
605611
defined in {eq}`def_dmo`, a density $\psi^*$ on $S$ is called
606-
*stationary* for $P$ if it is a fixed point of the operator $P$.
612+
**stationary** for $P$ if it is a fixed point of the operator $P$.
607613

608614
In other words,
609615

@@ -640,9 +646,9 @@ With additional conditions, we can also get a unique stationary density ($\psi \
640646
```
641647

642648
This combination of existence, uniqueness and global convergence in the sense
643-
of {eq}`statd_dca` is often referred to as *global stability*.
649+
of {eq}`statd_dca` is often referred to as **global stability**.
644650

645-
Under very similar conditions, we get *ergodicity*, which means that
651+
Under very similar conditions, we get **ergodicity**, which means that
646652

647653
```{math}
648654
:label: statd_lln
@@ -689,6 +695,7 @@ Here is such a figure.
689695
(statd_egs)=
690696
```{figure} /_static/lecture_specific/stationary_densities/solution_statd_ex2.png
691697
698+
Density sequences from four different initial conditions
692699
```
693700

694701
All sequences are converging towards the same limit, regardless of their initial condition.
@@ -818,6 +825,7 @@ Try running at `n = 10, 100, 1000, 10000` to get an idea of the speed of converg
818825
ϕ = norm()
819826
n = 500
820827
θ = 0.8
828+
rng = np.random.default_rng(1234)
821829
# == Frequently used constants == #
822830
d = np.sqrt(1 - θ**2)
823831
δ = θ / d
@@ -830,14 +838,15 @@ def p(x, y):
830838
"Stochastic kernel for the TAR model."
831839
return ϕ.pdf((y - θ * np.abs(x)) / d) / d
832840
833-
Z = ϕ.rvs(n)
841+
Z = ϕ.rvs(n, random_state=rng)
834842
X = np.empty(n)
843+
X[0] = 0
835844
for t in range(n-1):
836845
X[t+1] = θ * np.abs(X[t]) + d * Z[t]
837846
ψ_est = LAE(p, X)
838847
k_est = gaussian_kde(X)
839848
840-
fig, ax = plt.subplots(figsize=(10, 7))
849+
fig, ax = plt.subplots()
841850
ys = np.linspace(-3, 3, 200)
842851
ax.plot(ys, ψ_star(ys), 'b-', lw=2, alpha=0.6, label='true')
843852
ax.plot(ys, ψ_est(ys), 'g-', lw=2, alpha=0.6, label='look-ahead estimate')
@@ -882,10 +891,11 @@ Here's one program that does the job
882891
# == Define parameters == #
883892
s = 0.2
884893
δ = 0.1
885-
a_σ = 0.4 # A = exp(B) where B ~ N(0, a_σ)
894+
a_σ = 0.4 # A = exp(B) where B ~ N(0, a_σ**2)
886895
α = 0.4 # f(k) = k**α
887896
888897
ϕ = lognorm(a_σ)
898+
rng = np.random.default_rng(1234)
889899
890900
def p(x, y):
891901
"Stochastic kernel, vectorized in x. Both x and y must be positive."
@@ -906,8 +916,8 @@ for i in range(4):
906916
907917
# == Generate matrix s.t. t-th column is n observations of k_t == #
908918
k = np.empty((n, T))
909-
A = ϕ.rvs((n, T))
910-
k[:, 0] = ψ_0.rvs(n)
919+
A = ϕ.rvs((n, T), random_state=rng)
920+
k[:, 0] = ψ_0.rvs(n, random_state=rng)
911921
for t in range(T-1):
912922
k[:, t+1] = s * A[:,t] * k[:, t]**α + (1 - δ) * k[:, t]
913923
@@ -938,22 +948,23 @@ To illustrate, let's generate three artificial data sets and compare them with a
938948
The three data sets we will use are:
939949

940950
$$
941-
\{ X_1, \ldots, X_n \} \sim LN(0, 1), \;\;
951+
\{ X_1, \ldots, X_n \} \sim \mathrm{LN}(0, 1), \;\;
942952
\{ Y_1, \ldots, Y_n \} \sim N(2, 1), \;\;
943953
\text{ and } \;
944-
\{ Z_1, \ldots, Z_n \} \sim N(4, 1), \;
954+
\{ Z_1, \ldots, Z_n \} \sim N(4, 1)
945955
$$
946956

947957
Here is the code and figure:
948958

949959
```{code-cell} python3
950960
n = 500
951-
x = np.random.randn(n) # N(0, 1)
952-
x = np.exp(x) # Map x to lognormal
953-
y = np.random.randn(n) + 2.0 # N(2, 1)
954-
z = np.random.randn(n) + 4.0 # N(4, 1)
961+
rng = np.random.default_rng(1234)
962+
x = rng.standard_normal(n) # N(0, 1)
963+
x = np.exp(x) # Map x to lognormal
964+
y = rng.standard_normal(n) + 2.0 # N(2, 1)
965+
z = rng.standard_normal(n) + 4.0 # N(4, 1)
955966
956-
fig, ax = plt.subplots(figsize=(10, 6.6))
967+
fig, ax = plt.subplots()
957968
ax.boxplot([x, y, z])
958969
ax.set_xticks((1, 2, 3))
959970
ax.set_ylim(-2, 14)
@@ -1010,6 +1021,7 @@ J = 8
10101021
θ = 0.9
10111022
d = np.sqrt(1 - θ**2)
10121023
δ = θ / d
1024+
rng = np.random.default_rng(1234)
10131025
10141026
fig, axes = plt.subplots(J, 1, figsize=(10, 4*J))
10151027
initial_conditions = np.linspace(8, 0, J)
@@ -1018,9 +1030,9 @@ X = np.empty((k, n))
10181030
for j in range(J):
10191031
10201032
axes[j].set_ylim(-4, 8)
1021-
axes[j].set_title(f'time series from t = {initial_conditions[j]}')
1033+
axes[j].set_title(f'time series from $X_0 = {initial_conditions[j]:.1f}$')
10221034
1023-
Z = np.random.randn(k, n)
1035+
Z = rng.standard_normal((k, n))
10241036
X[:, 0] = initial_conditions[j]
10251037
for t in range(1, n):
10261038
X[:, t] = θ * np.abs(X[:, t-1]) + d * Z[:, t]

0 commit comments

Comments
 (0)