genpca

An R package for Generalized Principal Component Analysis (GPCA) and related matrix decompositions when data is observed in non-Euclidean inner-product spaces.

What is Generalized PCA?

Standard PCA assumes all observations and variables are equally important and that Euclidean distance is the appropriate similarity measure. However, many real-world datasets violate these assumptions:

GPCA extends standard PCA by incorporating row and column metrics (M and A) that encode prior knowledge about data structure, following the framework of Allen, Grosenick & Taylor (2014). The package also implements generalized PLS methods building on ideas from Beaton et al. (2016).

Key Features

Core Functionality

Advanced Methods

Integration

Backend Selection Guide

The default backend is method = "eigen". "auto" is opt-in: pass it explicitly to let a heuristic pick among "eigen", "spectra", and "randomized" based on problem shape and constraint structure.

Method Best for Pros Cons
eigen Small/medium problems, exact reference runs Most stable reference behavior Builds larger intermediate matrices; for very large sparse constraints may rely on truncated eigensolve (maxeig) and become slower/approximate
spectra Large problems with few components Iterative partial SVD of the whitened operator (eigencore); lower memory Both metrics are factored once (Cholesky or sparse Cholesky); a large dense general metric costs one factorization
randomized Wide (p >> n), sparse-metric, low-rank workloads Often fastest in wide settings; block GEMM/SpMM path Approximate by design; tune oversample, n_power, n_polish
deflation Few components with limited memory Low memory, component-by-component extraction Can converge slowly; C++ path currently expects sparse metrics
auto Default production usage Chooses among eigen/spectra/randomized heuristically Heuristics may not be optimal for every hardware/data regime

Installation

# install.packages("devtools")
devtools::install_github("bbuchsbaum/genpca")

You’ll also want these runtime dependencies installed:

install.packages(c("Matrix", "eigencore", "multivarious"))
# Optional for some utilities / tests
install.packages(c("irlba", "knitr", "rmarkdown"))

Quick Start

Basic Usage

library(genpca)
set.seed(1)
X <- matrix(rnorm(200 * 50), 200, 50)

# Standard PCA (identity metrics by default)
fit <- genpca(X, ncomp = 5, preproc = multivarious::center())
fit$sdev                             # generalized singular values;
                                      # with identity metrics this is
                                      # prcomp(X)$sdev * sqrt(nrow(X) - 1)
head(multivarious::scores(fit))      # scores (n × k)
head(multivarious::components(fit))  # loadings (p × k)

Weighted GPCA

# Example: Survey data with population weights
library(Matrix)
pop_weights <- runif(nrow(X), 0.5, 1.5)  # population sizes
M <- Diagonal(nrow(X), x = pop_weights)  # row metric

# Variable importance weights  
var_importance <- c(rep(2, 10), rep(1, 30), rep(0.5, 10))
A <- Diagonal(ncol(X), x = var_importance)  # column metric

fit_weighted <- genpca(X, M = M, A = A, ncomp = 5, 
                      preproc = multivarious::center())

Covariance-based GPCA

# When you have pre-computed covariance C = X'MX. fit_weighted above used
# preproc = multivarious::center(), so C must be built from centered X for
# the two fits to agree exactly.
Xc <- scale(X, center = TRUE, scale = FALSE)
C  <- crossprod(Xc, M %*% Xc)
fit_cov <- genpca_cov(C, R = A, ncomp = 5, method = "gmd")
# Mathematically equivalent to fit_weighted above
all.equal(fit_weighted$sdev, fit_cov$d, tolerance = 1e-8)

Generalized PLS

# Two-block analysis with canonical PLS
Y <- matrix(rnorm(200 * 20), 200, 20)
pls <- genpls(X, Y, ncomp = 3, 
              preproc_x = multivarious::center(), 
              preproc_y = multivarious::center())
pls$d                    # singular values of the whitened cross-product
                          # Xe'Ye (covariance scale, NOT canonical correlations)
dim(pls$vx); dim(pls$vy) # X/Y weight matrices

# To get canonical-correlation-like quantities, correlate the latent
# variable pairs directly:
diag(cor(pls$lx, pls$ly))

Understanding Metrics in GPCA

The metrics M and A define inner products and distances in the observation and variable spaces:

Row Metric M (n × n)

Column Metric A (p × p)

When M = I and A = I, GPCA reduces to standard PCA.

Documentation

Build locally:

devtools::build_vignettes()
browseVignettes("genpca")

Testing and guarantees

Run tests locally:

library(testthat)
library(pkgload)
pkgload::load_all()
testthat::test_dir("tests/testthat")

References

The methods in this package are based on:

For additional theoretical background on generalized decompositions, see:

License

MIT (see LICENSE).

Contributing

Issues and PRs welcome. Please open a ticket with a minimal example, your R session info, and (if relevant) a pointer to the metric matrices that reproduce the behavior.

Albers theme

This package uses the albersdown theme. Existing vignette theme hooks are replaced so albers.css and local albers.js render consistently on CRAN and GitHub Pages. The defaults are configured via params$family and params$preset (family = ‘red’, preset = ‘interaction’). The pkgdown site uses template: { package: albersdown } together with generated pkgdown/extra.css and pkgdown/extra.js so the theme is linked and activated on site pages.