Joint Gaussian reference imputer — algorithm as implemented¶
At a glance¶
| Item | Joint Gaussian imputer |
|---|---|
| Status | Implemented; see project status for validation maturity |
| Outcome | Continuous, fixed design waves |
| Missingness | MAR; delta-adjusted MNAR sensitivity |
| Dependence | Unstructured covariance across waves |
| Mean model | Wave-saturated (every predictor × every wave) |
| Parameter draw | Exact conjugate data augmentation (Jeffreys prior) |
| Outcome draw | Conditional multivariate normal |
| Main assumption | Approximately Gaussian outcome; participant-level predictors (A5, A8) |
| Do not use when | Count/bounded/strongly non-Gaussian outcomes; time-varying predictors |
Implementation: src/longmi/impute/gaussian.py. Theory: Proposition 2 of mathematical_foundations.md; sources: Schafer (1997, the NORM algorithm with regressors); Tanner & Wong (1987) for data augmentation.
Model¶
Participants \(i = 1, \dots, n\) observed at the \(J\) design waves; predictors \(x_i \in \mathbb{R}^K\) (intercept added automatically) constant within participant. The response vector follows the multivariate regression
with \(B \in \mathbb{R}^{K \times J}\) (a separate coefficient for every predictor at every wave) and unstructured \(\Sigma\). The mean model is fully saturated in time, so exposure-by-wave interactions are always present (A8) and any analysis linear in these predictors and time is nested.
Prior and exact conditionals¶
Jeffreys prior \(p(B, \Sigma) \propto |\Sigma|^{-(J+1)/2}\). Given complete data \((Y, X)\):
The matrix-normal draw is \(B = \widehat B + A Z L^\top\) with \(AA^\top = (X^\top X)^{-1}\), \(LL^\top = \Sigma\), \(Z\) a \(K \times J\) matrix of standard normals.
Data augmentation¶
- Initialize missing cells by per-wave OLS prediction from \(X\).
- Sweep (Tanner–Wong): P-step draws \((\Sigma, B)\) from the exact conditionals above given the current completed data; I-step redraws every missing cell from the conditional multivariate normal \(Y_i^{\mathrm{mis}} \mid Y_i^{\mathrm{obs}}, B, \Sigma\) (rows with no observed waves draw from the unconditional \(N(B^\top x_i, \Sigma)\) marginal on their missing coordinates).
- Keep a completed dataset after
burn_insweeps, then after every furtherthinsweeps, until \(M\) imputations exist. Both parameter and outcome uncertainty are propagated every sweep (A6). - An optional
DeltaAdjustmentshifts kept draws (identity link: linear-predictor and outcome scales coincide) for MNAR sensitivity. - Each kept matrix is passed to
LongitudinalData.completed_with, which re-validates preservation of observed values and complete filling.
The backend separates fitting from generation:
JointGaussianImputer.fit(data) returns a JointGaussianFit (validated
design, declaration, model specification, data fingerprint), and
fit.impute(m, random_state, delta=...) runs a fresh chain — scenario
runs with equal seeds share identical underlying draws, so a delta
scenario differs from MAR only by the deterministic shift.
Imputations come from a single chain separated by thin sweeps after
burn_in. Every run reports GaussianChainDiagnostics — per-sweep lag-1
autocorrelation and a crude single-chain ESS of the log det(Sigma)
trace, plus the autocorrelation at kept-imputation spacing — so the
adequacy of burn_in/thin is inspected from the run, not asserted from
the defaults (multi-chain R-hat/ESS arrive with the simulation suite).
All randomness flows through an integer seed or the caller's
numpy.random.Generator; the seed, bit generator, and package version
are recorded in the run metadata. Wave order follows the declared design
order (times=), which the backend requires unless constructed with
allow_undeclared_times=True.
Requirements and refusals¶
- continuous outcome only;
- complete participant-by-wave row grid (missing outcomes allowed, missing rows not);
- participant-level numeric predictors (time-varying predictors need the GLMM backends);
- \(n - K \ge J\), else the \(\Sigma\) posterior is improper — refused;
- \(M \ge 2\).
Validation¶
Unit tests (tests/unit/test_gaussian_imputer.py): mechanical invariants (preservation, reproducibility by seed, between-imputation variability, guards) and fixed-seed statistical checks — pooled recovery of a wave-specific treatment effect under sequential MAR dropout, pooled SE exceeding single-imputation SE with nonzero FMI, and the exact delta-shift property. Simulation-grid coverage and cross-language statistical comparison arrive with the simulation suite (PR 5).