GitHub profile

Step 1 - Specify the Prior

Notation

Unlike the first track's Step 1, where $\mathbf{W}$ is fixed at its classical value and only the score distribution's $\mu_i,\sigma_i^2$ get priors, here $\mathbf{W}$ itself is a free parameter:

$$\mathbf{W} \sim \text{Normal}(0, 1), \qquad \mathbf{W} \in \mathbb{R}^{N \times 3}$$

$$\sigma \sim \text{HalfNormal}(1)$$

$\boldsymbol{\mu}$ is fixed at $\mathbf{0}$ rather than given a prior — the data this model will eventually be fit to ($\widetilde{\mathbf{Y}}_c$, Classical PCA's Step 5 output) is already column-demeaned, so there's no free mean left to estimate.

These priors on $\mathbf{W}$ and $\sigma$ are proper, not flat/improper. The eventual likelihood only depends on $\mathbf{W}\mathbf{W}^\top$, so $\mathbf{W}$ is non-identified up to rotation — combined with an improper prior, that non-identifiability would leave the posterior non-normalizable. No identifiability constraint is imposed on $\mathbf{W}$ at this stage; that decision is deferred to whichever step first attaches a likelihood and samples the model.

No likelihood is attached at this stage, so there is nothing to sample or plot yet — same starting point as the first track's Step 1.

Python

filename: step1_prior.py

import pymc as pm

'''
prior for the full-latent model: W (loadings, N x k) and sigma (noise scale) are free
parameters here, in contrast to bayesian/step1_prior.py where W is kept fixed at its
classical value. mu is fixed at 0 rather than given a prior, since the input data
(dataframes/step5_demeaning.py::demeaning()) is already column-demeaned.

W's prior must be proper (not flat), unlike the mu_i priors in bayesian/step1_prior.py.
the likelihood here will only depend on W @ W.T, so W is non-identified up to rotation -
combined with an improper prior that would give a non-normalizable posterior. no
identifiability constraint is imposed yet; that's deferred to the sampling step.
'''

def prior_model(n_maturities=71, n_components=3):
    with pm.Model() as model:
        W = pm.Normal("W", mu=0, sigma=1, shape=(n_maturities, n_components))
        sigma = pm.HalfNormal("sigma", sigma=1)
    return model
proper Normal prior on the N x 3 loading matrix W, HalfNormal prior on the noise scale sigma; mu fixed at 0