Skip to content

Add Logistic PCA (LPCA) analysis - #500

Open
Jeebjean wants to merge 18 commits into
Reed-CompBio:mainfrom
Jeebjean:lpca-integration
Open

Add Logistic PCA (LPCA) analysis#500
Jeebjean wants to merge 18 commits into
Reed-CompBio:mainfrom
Jeebjean:lpca-integration

Conversation

@Jeebjean

@Jeebjean Jeebjean commented Jul 10, 2026

Copy link
Copy Markdown

Summary

Adds Logistic PCA (LPCA) as a new SPRAS analysis method. LPCA is the binary-data counterpart to the existing PCA analysis. It is designed for binary matrices (0/1) like the edge-by-run matrix built from pathway reconstruction outputs, whereas standard PCA assumes continuous data.

Changes

New config block

analysis.lpca with five options:

  • include: enable/disable LPCA (default false)
  • k: number of principal components (default 2)
  • m: logisticPCA tuning parameter, used when cv is false (default 6)
  • cv: if true, determine m by cross-validation; if false, use fixed m (default false)
  • transpose: if false, run LPCA on edges x runs matrix (one embedding per edge);
    if true, run on runs x edges matrix (one embedding per pathway run,
    mirrors the classic PCA analysis) (default false)

New Snakemake rule lpca_analysis

  • Restricted to algorithms with multiple parameter combinations (same guard as per-algorithm PCA)
  • Outputs per algorithm: {algorithm}-lpca-scores.csv, {algorithm}-lpca.png, {algorithm}-lpca-coordinates.txt

New module spras/analysis/lpca.py

  • Builds the binary matrix via summarize_networks
  • Optionally transposes the matrix
  • Runs the logisticPCA container via run_container_and_log
  • Generates a PC1 vs PC2 scatterplot and saves coordinates

New Docker wrapper docker-wrappers/lpca/

  • Pinned rocker/r-base:4.4.2 Dockerfile installing logisticPCA and ggplot2
  • run_lpca.R: runs LPCA and saves scores + deviance explained
  • run_cv.R: cross-validation to find optimal m
  • README documenting config options and Docker image publication

Unit tests test/analysis/test_lpca.py

  • 3 tests: output file existence, score shape (edges x k), score shape (runs x k with transpose)

Docker timeout

  • Increased from 60s to 600s in containers.py to handle larger binary matrices

Testing locally

Build the image and run the pipeline:

docker build -t reedcompbio/lpca:v1 docker-wrappers/lpca/

Enable analysis.lpca.include: true in your config and run as usual.
Tested end-to-end with OmicsIntegrator2 (216 combos) and MincostFlow (14 combos).

Before / at merge

The image must be published to reedcompbio/lpca:v1 on Docker Hub by a maintainer:

docker build -t reedcompbio/lpca:v1 docker-wrappers/lpca/
docker push reedcompbio/lpca:v1

cc @agitter @ntalluri

Jeebjean added 2 commits July 10, 2026 11:28
Adds an analysis.lpca config block (include, k, m, cv, transpose) with a matching LpcaAnalysis schema, an lpca_analysis Snakemake rule restricted to algorithms with multiple parameter combinations, and an LPCA analysis module that builds the binary edge-by-run matrix via summarize_networks and runs the logisticPCA container through run_container_and_log. m is fixed by default; cross-validation and matrix transposition are opt-in.
Adds docker-wrappers/lpca with a pinned rocker/r-base Dockerfile that installs logisticPCA and its ggplot2 dependencies, the run_lpca.R and run_cv.R scripts under /app, and a README documenting the config options, script contracts, and how to build and publish reedcompbio/lpca:v1.
@read-the-docs-community

read-the-docs-community Bot commented Jul 10, 2026

Copy link
Copy Markdown

Documentation build overview

📚 spras | 🛠️ Build #33784013 | 📁 Comparing b1905c0 against latest (1cb9d03)

  🔍 Preview build  

3 files changed
± genindex.html
± fordevs/spras.config.html
± fordevs/spras.html

@Jeebjean
Jeebjean marked this pull request as ready for review July 21, 2026 21:07

@agitter agitter left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this will close #271 when merged.

I pushed the image to DockerHub: https://hub.docker.com/r/reedcompbio/lpca

We should add this to our Docker image building test: https://github.com/Reed-CompBio/spras/blob/main/.github/workflows/build-containers.yml

This comment should be modified to note the alternative LPCA

# TODO: replace PCA https://github.com/Reed-CompBio/spras/issues/271

I didn't comment on every detail yet, but in general there are some small things we can to do make this more like the existing PCA.

Comment thread config/config.yaml
Comment thread config/config.yaml
Comment thread config/config.yaml
Comment thread docker-wrappers/lpca/README.md Outdated
Comment thread docker-wrappers/LPCA/Dockerfile
Comment thread spras/analysis/lpca.py Outdated
Comment thread spras/analysis/lpca.py Outdated
Comment thread spras/analysis/lpca.py
Comment thread spras/analysis/lpca.py
Comment thread spras/analysis/lpca.py Outdated

@agitter agitter left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional comments because I accidentally submitted the first batch before finishing.

Comment thread spras/containers.py
# Initialize a Docker client using environment variables
try:
client = docker.from_env()
client = docker.from_env(timeout=600)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still needed? Was it a workaround for the memory issues?

This modifies Docker but not Singularity.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 600s timeout is still needed. Large matrices (e.g. RWR with ~20k edges) can take several minutes even with partial_decomp=TRUE. Singularity is unaffected.

Comment thread test/analysis/test_lpca.py Outdated
OUT_DIR.mkdir(parents=True, exist_ok=True)

@skip_if_no_lpca_image
def test_lpca_output_exists(self):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A stronger test would be that the expected output is created when we use known inputs. These are okay first steps, but if there is time we would add the stronger test.

There is some degeneracy with these existing pathways though that cause the PCA tests to fail at random. It may be okay here because we don't do KDE testing.

Will we need to account for sign non-identifiability in LPCA?

Comment thread Snakefile
Comment thread Snakefile Outdated
Comment thread Snakefile Outdated
ml.hac_horizontal(summary_df, output.hac_image_horizontal, output.hac_clusters_horizontal, **hac_params)
ml.pca(summary_df, output.pca_image, output.pca_variance, output.pca_coordinates, **pca_params)

rule lpca_analysis:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a new rule or a conditional extension of ml_analysis and ml_analysis_aggregate_algo?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept it as a separate rule to avoid touching existing ml_analysis logic. Happy to refactor it as a conditional extension and add cross-algorithm support if that's the preferred direction before merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants