Sparse planar MFPCA / joint PACE¶
fit_sparse_mfpca() is the stable 1.x route for jointly observed sparse planar gaze when x and y are observed at the same retained native timestamps within each curve. The estimator was introduced and scientifically qualified in the 0.12 line and is part of the frozen 1.0 compatibility baseline.
When should I use this?¶
Use the estimator when x(t) and y(t) are both scientific functional coordinates, observations are sparse/irregular enough that pre-interpolating every raw trajectory would manufacture much of the analyzed curve, x and y are paired at the same retained timestamps, and cross-channel covariance is part of the target.
For one sparse functional coordinate, use fit_sparse_fpca(). For defensibly common-grid planar trajectories, use fit_mfpca().
When should I not use it?¶
Do not use sparse MFPCA merely because timestamps differ slightly across otherwise dense curves. Do not use it when x and y have unmatched retained timestamps within a curve. Do not replace an unpaired observation process with silent alignment.
Observation contract¶
For curve i and paired native time t_ij,
The native sparse sample is preserved. Fitted population functions are later evaluated at native times for conditional scoring; that is fitted-model evaluation, not raw-trajectory interpolation.
The joint planar model¶
with
while generally
Why two separate x/y PACE fits are not equivalent¶
Two independent univariate models discard C_xy and C_yx. They can recover marginal x and y modes, but they do not estimate the eigenfunctions of the joint planar covariance operator and do not produce joint conditional scores.
Directional cross-covariance products¶
Latent covariance smoothing uses temporally off-diagonal within-curve products, including cross-channel products with j != l. Same-index products are excluded so contemporaneous measurement-error covariance is not absorbed into the latent cross-channel surface under the declared error model.
Full joint PSD handling¶
With quadrature matrix W,
PSD inspection/projection is applied to the joint weighted operator, not independently to C_xx and C_yy.
Measurement error¶
The stable API does not silently estimate an arbitrary cross-channel noise covariance. Use a defensible declared structure/variance and report it.
Joint PACE scoring¶
For m_i paired native observations,
and
The conditional system uses the full fitted joint covariance, not a rank-K reconstruction. n_components controls only the returned eigensystem/scores.
Minimal fit¶
import numpy as np
from eyetrajectoriespy import fit_sparse_mfpca
fit = fit_sparse_mfpca(
irregular,
dimensions=("x", "y"),
n_components=2,
evaluation_grid=np.linspace(0.0, 1.0, 41),
mean_bandwidth=0.20,
covariance_bandwidth=0.30,
measurement_error="diagonal",
measurement_error_variance=(0.0025, 0.0025),
psd_action="project",
score_ridge=0.0,
score_failure_action="retain_nan",
)
Audited bandwidth selection¶
The 1.1 development line adds a dedicated, opt-in selector without changing fit_sparse_mfpca() defaults or the frozen 1.0 root API:
from eyetrajectoriespy.sparse_multivariate_bandwidth_selection import (
select_sparse_mfpca_bandwidths,
sparse_mfpca_bandwidth_selection_reporting_text,
)
selection = select_sparse_mfpca_bandwidths(
irregular,
dimensions=("x", "y"),
evaluation_grid=np.linspace(0.0, 1.0, 41),
mean_bandwidths=(0.10, 0.20, 0.35),
covariance_bandwidths=(0.20, 0.30, 0.50),
measurement_error="diagonal",
measurement_error_variance=(0.0025, 0.0025),
n_splits=5,
resampling_unit="curve",
psd_action="project",
)
print(selection.selected_bandwidths)
print(sparse_mfpca_bandwidth_selection_reporting_text(selection))
Each candidate refits only the planar population mean and full latent covariance surfaces from training curves. Held-out native curves are evaluated by Gaussian negative log predictive density using the full Cxx/Cxy/Cyx/Cyy covariance plus the fixed declared 2x2 measurement-error covariance. Joint-PACE scores are not fitted or used as the selection criterion, and score ridge is not added to the held-out predictive covariance.
For repeated trials, use group resampling so all trials from a participant stay in the same fold:
selection = select_sparse_mfpca_bandwidths(
irregular,
dimensions=("x", "y"),
evaluation_grid=np.linspace(0.0, 1.0, 41),
mean_bandwidths=(0.10, 0.20, 0.35),
covariance_bandwidths=(0.20, 0.30, 0.50),
measurement_error="fixed_matrix",
measurement_error_covariance=error_covariance,
n_splits=5,
resampling_unit="group",
group_column="participant_id",
psd_action="project",
)
The selector retains candidate/fold failures, fold assignments, per-curve losses, predictive covariance diagnostics, candidate summaries, and deterministic selection provenance. Measurement error, component rank, score ridge, evaluation grid, PSD policy, and support policy are not tuned in this tranche.
Selected values must be passed explicitly to the fitter:
selected = selection.selected_bandwidths
if selected is None:
raise RuntimeError("no eligible bandwidth candidate")
fit = fit_sparse_mfpca(
irregular,
dimensions=("x", "y"),
n_components=2,
evaluation_grid=np.linspace(0.0, 1.0, 41),
mean_bandwidth=float(selected["mean_bandwidth"]),
covariance_bandwidth=float(selected["covariance_bandwidth"]),
measurement_error="diagonal",
measurement_error_variance=(0.0025, 0.0025),
psd_action="project",
)
The selection criterion is predictive and does not define a unique population-optimal or "true" smoothing bandwidth. A 1-SE rule is deliberately absent because no scalar simplicity ordering has been predeclared for the two-dimensional bandwidth tuple.
See the sparse-MFPCA bandwidth-selection qualification for the known-truth selection design and exact evidence boundary.
Understanding SparseMFPCAResult¶
The result retains mean, eigenfunctions, eigenvalues, joint PACE scores, the C_xx/C_xy/C_yx/C_yy covariance blocks, measurement-error covariance and quadrature weights, support/pair counts, score diagnostics, units, curve IDs, metadata, and provenance.
Score diagnostics and failure codes¶
Inspect result.score_diagnostics before downstream use. score_failure_action="retain_nan" keeps failed conditional systems visible rather than silently removing curves or replacing scores.
Conditional joint-PACE score uncertainty¶
The 1.1 development line adds a dedicated, additive uncertainty surface without changing fit_sparse_mfpca() defaults or the frozen 1.0 root API:
from eyetrajectoriespy.sparse_multivariate_score_uncertainty import (
sparse_mfpca_score_uncertainty,
sparse_mfpca_score_uncertainty_frame,
sparse_mfpca_score_uncertainty_reporting_text,
)
uncertainty = sparse_mfpca_score_uncertainty(fit, irregular)
print(sparse_mfpca_score_uncertainty_frame(uncertainty).head())
print(sparse_mfpca_score_uncertainty_reporting_text(uncertainty))
For retained score vector \(\boldsymbol\xi_i\), the reported covariance is
This calculation reuses the exact native joint-PACE score system: full fitted C_xx/Cxy/Cyx/Cyy covariance, time_major_interleaved_xy observation order, the declared 2x2 measurement-error covariance as \(I_m\otimes\mathbf R_\epsilon\), and the fitted score ridge. It uses linear solves rather than an explicit inverse and does not interpolate raw sparse trajectories.
The scope is intentionally narrow. The result is conditional on the fitted joint mean/covariance/eigensystem, measurement-error covariance, support policy, and score regularization. It does not include uncertainty from estimating those population objects, bandwidth selection, joint PSD repair, or measurement-error estimation. It also does not support asynchronous x/y observation grids.
See the joint-PACE score-uncertainty qualification for the oracle-population calibration design and exact evidence boundary.
Plots¶
Stable 1.0.0 includes four public visualization helpers that operate only on quantities already retained by SparseMFPCAResult:
from eyetrajectoriespy import (
plot_sparse_mfpca_component,
plot_sparse_mfpca_covariance_blocks,
plot_sparse_mfpca_cross_covariance,
plot_sparse_mfpca_score_diagnostics,
)
plot_sparse_mfpca_component(fit, component=0)
plot_sparse_mfpca_covariance_blocks(fit, stage="used")
plot_sparse_mfpca_cross_covariance(fit, stage="used")
plot_sparse_mfpca_score_diagnostics(fit)
plot_sparse_mfpca_component() interprets the retained vector eigenfunction as coordinate-specific mean ± mode curves. plot_sparse_mfpca_covariance_blocks() displays all four covariance blocks together. plot_sparse_mfpca_cross_covariance() keeps the directional C_xy/C_yx orientation explicit. plot_sparse_mfpca_score_diagnostics() shows conditional-system conditioning against paired native observation counts and preserves failed/non-finite systems as visible diagnostics.
For covariance plots, stage="used" displays the blocks after the declared joint PSD policy—the blocks actually used downstream—whereas stage="smoothed" displays the retained directly smoothed pre-PSD blocks. Neither option refits or resmooths the model.
Recovery and comparator evidence¶
Use the native sparse-MFPCA recovery, sparse-MFPCA bandwidth-selection qualification, joint-PACE score-uncertainty qualification, comparator sensitivity, and stress/performance pages. Population eigenspace recovery, bandwidth-selection behavior, individual joint-PACE score recovery, and conditional score uncertainty are distinct targets.
The core scientific-method evidence remains traceable to the 0.12 estimator programme. Final 1.0.0 subsequently reran the exact-version package, sparse-MFPCA, cross-platform, performance and external-comparator qualification matrix without changing the estimator's scientific contract.
Reporting¶
from eyetrajectoriespy import sparse_mfpca_reporting_text, sparse_mfpca_score_frame
print(sparse_mfpca_score_frame(fit).head())
print(sparse_mfpca_reporting_text(fit))
Report native sampling, paired-timestamp requirements, analysis grid/support, mean/covariance bandwidths, measurement-error covariance, PSD action, score ridge/failure policy, retained components, and failed-score counts. If bandwidths were selected with the 1.1 selector, report the candidate grid, resampling unit/group column, fold count, predictive criterion, failed candidates/folds, selected pair, fixed measurement-error specification, and that the values were passed explicitly to the fitter. If conditional score uncertainty is reported, state explicitly that it conditions on the fitted joint population objects and declared measurement-error covariance and excludes population-estimation and bandwidth uncertainty.
Limitations¶
The stable 1.x estimator does not imply automatic bandwidth selection, arbitrary unpaired x/y observation times, automatic cross-channel noise estimation, full uncertainty propagation from sparse population estimation into joint scores or downstream models, or equivalence to dense-grid projection scores. The 1.1 bandwidth selector is a separate predictive-CV audit layer and does not define a unique true bandwidth or propagate selection uncertainty. The 1.1 conditional uncertainty surface covers only the fitted-population joint-PACE posterior covariance described above. The plotting helpers are views over retained fitted quantities and do not alter any of those scientific boundaries.