coco_pipe.transforms.temporal_alignment ======================================= .. py:module:: coco_pipe.transforms.temporal_alignment .. autoapi-nested-parse:: Group-aware alignment of temporal trajectories. Classes ------- .. autoapisummary:: coco_pipe.transforms.temporal_alignment.TemporalProcrustesAlignment Module Contents --------------- .. py:class:: TemporalProcrustesAlignment(n_components = 30, *, adaptation = 'transductive', rotate = True, use_shared_basis = False, augment = (), augment_only = False, trajectory_metrics = None, random_state = 42) Bases: :py:obj:`sklearn.base.BaseEstimator`, :py:obj:`sklearn.base.TransformerMixin` Align participant-specific PCA trajectories to a training template. ``fit`` learns a shared PCA template and participant mappings from the training fold. ``transform`` reuses stored mappings for known participants and estimates a label-free PCA/rotation from the transform batch for unseen participants. The latter is explicit transductive adaptation. Two options turn this into its own controls. ``rotate=False`` keeps the per-participant PCA but drops the Procrustes step, which isolates whether a participant-specific basis alone transfers (it does not) or whether the rotation is what does the work. ``adaptation="calibration"`` estimates an unseen participant's PCA and rotation from one random half of their trials and applies it to the other half (and vice versa), so no trial ever contributes to its own mapping — a non-transductive variant that still returns every row. ``use_shared_basis=True`` is a third control: every participant is projected through the pooled training template directly (the same ``shared_pca_`` fit ``fit()`` already uses as the rotation target), ignoring per-participant identity and ``rotate`` entirely. This is the continuous, temporally-stable analogue of a single spatial filter shared by everyone — as opposed to ``coco_pipe.decoding``'s ``ReducerConfig`` PCA, which is fold-local but refit independently at every sliding-window latency. ``augment`` concatenates extra channels derived from each component's own trajectory onto the raw scores, still computed fold-locally inside ``transform`` so nothing about a held-out participant leaks into them: ``"envelope"`` (Hilbert amplitude), ``"velocity"`` (index-based first derivative — only rank-invariant reparametrizations of time reach the classifier, and any downstream ``StandardScaler`` absorbs a fixed sampling-rate scale factor, so the true sampling interval isn't needed), and ``"scalar"`` (each component's peak amplitude, index-based peak latency, mean power, and signed AUC over the whole supplied window, broadcast as constant channels across time). Requesting ``n`` of these turns ``n_components`` raw channels into ``n_components * (1 + n)``. ``augment_only=True`` drops the raw per-component ``scores`` channels entirely, leaving only whatever ``augment`` requests (e.g. just the ~10 ``"trajectory"`` geometry channels, independent of ``n_components`` - for analyses where the raw PC scores aren't wanted as features at all, only derived channels computed from the embedding they define). ``trajectory_metrics`` restricts ``"trajectory"`` to a chosen subset of its ~10 metrics (by name, e.g. ``("speed",)``) instead of computing and returning all of them - ``None`` (default) means all. .. py:attribute:: fold_local :value: True .. py:attribute:: n_components :value: 30 .. py:attribute:: adaptation :value: 'transductive' .. py:attribute:: rotate :value: True .. py:attribute:: use_shared_basis :value: False .. py:attribute:: augment :value: () .. py:attribute:: augment_only :value: False .. py:attribute:: trajectory_metrics :value: None .. py:attribute:: random_state :value: 42 .. py:method:: fit(X, y = None, groups = None) Fit the training-fold template and participant mappings. .. py:method:: transform(X, groups = None) Project and align known or unseen participant trajectories. .. py:method:: fit_transform(X, y = None, groups = None, **fit_params) Fit and align one training fold.