Source code for mir.embedding.pca

"""PCA denoising of TCREMP embeddings.

The raw prototype-distance coordinates are highly redundant — neighbouring
prototypes and correlated V/J scores span a low-rank subspace (Theory T3). A
``StandardScaler`` → ``PCA`` step smooths the embedding, removes that redundancy,
and yields a compact basis that is well behaved for clustering / visualization
(the paper uses ``n_components=50``).
"""

from __future__ import annotations

import numpy as np
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler


[docs] def pca_denoise( X: np.ndarray, n_components: int = 50, scale: bool = True, random_state: int = 0 ) -> np.ndarray: """Standardize then PCA-reduce a TCREMP embedding. Args: X: ``(n_clonotypes, n_features)`` embedding. n_components: Target dimensionality (clamped to ``min(n_samples, n_features)``). scale: Standardize each coordinate to zero mean / unit variance first. random_state: Seed for the (randomized) SVD solver. Returns: ``(n_clonotypes, k)`` float array of principal-component scores, ``k = min(n_components, n_samples, n_features)``. """ if scale: X = StandardScaler().fit_transform(X) k = min(n_components, X.shape[0], X.shape[1]) return PCA(n_components=k, random_state=random_state).fit_transform(X)
if __name__ == "__main__": rng = np.random.default_rng(0) # low-rank signal + noise -> PCA should recover the rank Z = rng.standard_normal((200, 5)) @ rng.standard_normal((5, 300)) Y = pca_denoise(Z + 0.01 * rng.standard_normal((200, 300)), n_components=50) assert Y.shape == (200, 50) # variance concentrates in the first few PCs var = Y.var(axis=0) assert var[:5].sum() > 0.9 * var.sum(), var[:8] print("mir.embedding.pca self-check OK; top-5 PC var fraction", round(float(var[:5].sum() / var.sum()), 3))