Step 2 - Build the Probabilistic Model
Notation
Step 1 defined the (improper) prior on $\mu_i, \sigma_i^2$ for each component $i$. This step attaches the likelihood, completing the model:
$$z_i \sim \text{Normal}(\mu_i, \sigma_i^2), \qquad i \in {1,2,3}$$
where $z_i$ is the observed vector of that component's scores from Step 9 (Classical PCA). Combining the improper prior with this likelihood is what makes the model proper again — the posterior integrates to 1 even though the prior alone didn't (see Priors — Proper vs improper priors). Each component is modelled independently, so there are three separate (mu, sigma, likelihood) groups in the one model rather than a joint/correlated structure.
The model built here is still unsampled — Step 3 runs MCMC over it to get the posterior.
Python
filename: step2_model.py
import pymc as pm
from dataframes.step9_scores import scores
from bayesian.step1_prior import prior_model
'''
extends the step 1 prior with a Normal likelihood for each component's observed scores:
z_i ~ Normal(mu_i, sigma_i), independently per component.
'''
def build_model(components=("PC1", "PC2", "PC3")):
df = scores()
model = prior_model(components)
with model:
for component in components:
pm.Normal(
f"z_{component}",
mu=model[f"mu_{component}"],
sigma=model[f"sigma_{component}"],
observed=df[component].values,
)
return model
reopens the Step 1 prior model and attaches a Normal likelihood per component, observed against that component's actual scores