Every model in this course is a probabilistic recipe: a description of how data could arise.
Today: for each of several examples, we see
We’ll go through five examples, roughly in order of increasing complexity:
A rather silly example, just to illustrate the principles.
Experiment to match: someone flips a coin \(n\) times and tells us only how many came up heads.
\[ X_i\overset{\text{iid}}\sim\operatorname{Bernoulli}(p),\quad i=1,\ldots,n, \qquad Y=\sum_{i=1}^n X_i. \]
We simulate every trial, then return only the total, matching what the experiment actually reports. \(Y\) is random even though the sum is a deterministic function because that function takes random variables as arguments.
| Math | R | Python | Role |
|---|---|---|---|
| \(n\), \(p\) | function arguments | function arguments | supplied |
| \(X_i\) | x, one entry per trial |
x, one entry per trial |
random |
| iid structure | one vectorized rbinom(n, ...) call |
one vectorized rng.binomial(1, p, size=n) call |
shared across \(i\) |
| \(Y=\sum_i X_i\) | sum(x) |
x.sum() |
random (computed) |
By the way: Summing \(n\) iid \(\operatorname{Bernoulli}(p)\) trials is common enough that its exact distribution has been worked out: \(Y\) is exactly \(\operatorname{Binomial}(n,p)\), and both R (rbinom(1, n, p)) and Python (rng.binomial(n, p)) let you draw it directly. Much of what we build this semester won’t be common enough to have that kind of built-in answer, in which case we’ll have to build the models more explicitly.
Markov language models are examples of a generative model for which a fairly parsimonious description can still generate long, varied output.
\(W_t\) is the actual word generated at position \(t\). \(A\) is a transition table, estimated from a passage of text; its row \(A_{w,\cdot}\) gives the conditional distribution of the next word given that the current word is \(w\).
\[ W_1 = w_{\text{start}}, \qquad W_t \mid W_{t-1} \sim \operatorname{Categorical}\big(A_{W_{t-1},\,\cdot}\big), \quad t=2,\ldots,T. \]
\(w_{\text{start}}\) is a supplied starting word, and so \(W_1\) is not random here.
We would normally estimate \(A\) from real text (shown in code associated with the lecture), then treat it as a fixed, supplied parameter. The estimation is not normally done with the sorts of methods described in this course.
R
| Math | R | Python | Role |
|---|---|---|---|
| the passage of text | corpus_text, tokenized into tokens |
corpus_text, tokenized into tokens |
used once, to build the parameter |
| \(A\) | transition_prob, one row per word |
transition_prob, one dict entry per word |
supplied parameter |
| \(W_1=w_{\text{start}}\) | generated[1] |
generated[0] |
supplied |
| \(W_{t-1}\) | generated[t - 1] |
generated[-1] |
tracks position in the chain |
| \(W_t\mid W_{t-1}\) | one sample() call per step, from row
current of transition_prob |
one rng.choice() call per step, from
transition_prob[current] |
random |
| full sequence \(W_{1:T}\) | generated, returned |
generated, returned |
observed |
The current word → sample next word → append → repeat loop is how we simulate from the model.
In the Markov model, everything we generated was returned. That’s not always true.
A generative model can include latent variables (quantities that are defined by the model/simulator but never returned/observed) either because they make the rule simpler or more realistic to state.
The hidden Markov model is our first example: an unobserved state sequence drives what we actually observe.
Concrete version: \(Z_t\) is which regime the economy is in this quarter (recession or expansion) and \(Y_t\) is a noisy indicator we actually observe, like GDP growth, whose typical level and volatility depend on the regime. We see \(Y_t\); the regime \(Z_t\) itself is never directly observed, only inferred. This is related to a real macroeconomic model.
\[ Z_1\sim\operatorname{Categorical}(\pi), \qquad Z_t\mid Z_{t-1}\sim\operatorname{Categorical}(A_{Z_{t-1},\cdot}), \]
\[ Y_t\mid Z_t=k\sim\operatorname{Normal}(\mu_k,\sigma_k^2). \]
R
| Math | R | Python | Role |
|---|---|---|---|
| \(\pi\), \(A\), \(\mu_k\), \(\sigma_k\) | function arguments | function arguments | supplied, fixed for the run |
| \(Z_1\sim\operatorname{Categorical}(\pi)\) | one draw before the loop (z[1]) |
one draw before the loop (z[0]) |
random |
| \(Z_t\mid Z_{t-1}\) | one draw per step, indexed by z[t-1] |
one draw per step, indexed by z[t-1] |
random, depends on previous state |
| \(Y_t\mid Z_t\) | one draw per step, indexed by z[t] |
one draw per step, indexed by z[t] |
random, depends on current state |
| full sequence \(Z_{1:T}\) | usually discarded in practice | usually discarded in practice | latent |
| full sequence \(Y_{1:T}\) | returned | returned | observed |
Topic models are generative models that don’t give a great description of all of the structure in the data they are attempting to model (documents), but they nonetheless can give good summaries.
\(\theta_d\) represents how much document \(d\) is about each topic (e.g., 70% sports, 30% cooking). \(z_{d,n}\) represents which single topic word \(n\) actually came from. \(w_{d,n}\) is the word itself.
\[ \underbrace{\theta_d\sim\operatorname{Dirichlet}(\alpha)}_{\text{topic mixture}} \quad\longrightarrow\quad \underbrace{z_{dn}\sim\operatorname{Categorical}(\theta_d)}_{\text{topic for word }n} \quad\longrightarrow\quad \underbrace{w_{dn}\sim\operatorname{Categorical}(\beta_{z_{dn}})}_{\text{observed word}}. \]
R
| Math | R | Python | Role |
|---|---|---|---|
| \(\alpha\), \(\beta\) | function arguments | function arguments | supplied |
| \(\theta_d\sim\operatorname{Dirichlet}(\alpha)\) | rdirichlet1(alpha), once per document |
rng.dirichlet(alpha), once per document |
random |
| \(z_{d,n}\mid\theta_d\) | sample.int(..., prob = theta_d) |
rng.choice(..., p=theta_d) |
random |
| \(w_{d,n}\mid z_{d,n}\) | one sample() call per word, from row z[n]
of beta |
one rng.choice() call per word, from
beta[z[n], :] |
random |
| \(\theta_d\) | topic_proportions[d, ], kept for inspection |
topic_proportions[d], kept for inspection |
ordinarily latent |
| \(w_{d,1},\ldots,w_{d,N}\) | documents[[d]], returned |
documents[d], returned |
observed |
Base R has no rdirichlet(); we draw one by drawing
independent Gammas and normalizing — a standard construction.
This model correspondsn to an actual assumed scientific mechanism of how infection spreads through a population.
\(S_t, I_t, R_t\) are counts of people in each health state at time \(t\). \(\Delta I_t\) is how many people newly became infected this step; \(\Delta R_t\) is how many newly recovered.
\[ \underbrace{S}_{\text{Susceptible}} \xrightarrow{\ \beta SI/N\ } \underbrace{I}_{\text{Infectious}} \xrightarrow{\ \gamma I\ } \underbrace{R}_{\text{Recovered}} \]
This continuous-time picture is the usual way SIR is drawn, but it hides exactly how event times are generated. The discrete-time version here keeps the same story and is more transparent to simulate from.
At each time step \(t = 0, 1, \ldots\), with population size \(N = S_t+I_t+R_t\) fixed:
\[ \Delta I_t \mid S_t, I_t \sim \operatorname{Binomial}\!\Big(S_t, 1-(1-\beta/N)^{I_t}\Big), \qquad \Delta R_t \mid I_t \sim \operatorname{Binomial}(I_t, \gamma), \]
Intuition for the success probability: each of the \(I_t\) infectious people independently infects a given susceptible person with probability \(\beta/N\) this step, so \((1-\beta/N)^{I_t}\) is the chance that person escapes all of them, and \(1-(1-\beta/N)^{I_t}\) is the chance they get infected by at least one.
\[ S_{t+1} = S_t - \Delta I_t, \qquad I_{t+1} = I_t + \Delta I_t - \Delta R_t, \qquad R_{t+1} = R_t + \Delta R_t. \]
R
| Math | R | Python | Role |
|---|---|---|---|
| \(\beta,\gamma,S_0,I_0,R_0,T\) | function arguments | function arguments | supplied |
| \(\Delta I_t\mid S_t,I_t\) | rbinom(1, S[t], p_infect) |
rng.binomial(S[t], p_infect) |
random |
| \(\Delta R_t\mid I_t\) | rbinom(1, I[t], gamma) |
rng.binomial(I[t], gamma) |
random |
| \(S_{t+1},I_{t+1},R_{t+1}\) | the three update lines right after the draws | the three update lines right after the draws | random (computed) |
| trajectory \((S_t,I_t,R_t)_{t=0}^T\) | data.frame(...), returned |
dict, returned |
this run’s realized epidemic |
\[ \begin{aligned} T_i^{\text{arr}} &= \textstyle\sum_{j\le i} A_j, \\ T_i^{\text{start}} &= \max\!\left(T_i^{\text{arr}},\, T_{i-1}^{\text{dep}}\right), \\ T_i^{\text{dep}} &= T_i^{\text{start}} + S_i, \\ W_i &= T_i^{\text{start}} - T_i^{\text{arr}}. \end{aligned} \]
The \(\max(\cdot)\) is the key line: customer \(i\)’s service can’t start before either their own arrival or the previous customer’s departure — whichever comes later.
Optional: hit a waiting-time target, push \(\lambda\ge\mu\), try constant service times.