PROTRIDER is an autoencoder-based method to call protein outliers from mass spectrometry-based proteomics datasets.
Have a look at our paper for information about our work.
Table of Contents
# 1. Install
pip install protrider
# 2. Run on the included sample data
protrider run --config config.yaml
# 3. Plot results
protrider plot --config config.yaml allResults are written to the directory specified by out_dir in config.yaml (default: output/). The key output file is protrider_summary.csv, which contains outlier calls with p-values, z-scores, and fold changes for every sample–protein pair.
PROTRIDER was tested using Python 3.14 on Linux. We recommend a dedicated conda environment:
conda create --name protrider_env python=3.14
conda activate protrider_env
pip install protriderVerify the installation:
protrider --helpMore information on conda environments can be found in Conda's user guide.
To install this fork from GitHub (instead of PyPI), clone mityasmirnov/PROTRIDER, then run uv sync or pip install -e . in the repository root.
All parameters are set in a YAML configuration file. A template is provided as config.yaml.
Input files are specified in the config:
input_intensities: CSV, TSV, or Parquet file with protein intensities (columns = samples, rows = proteins)sample_annotation(optional): CSV or TSV file with sample covariates (one row per sample)
An example dataset is included under sample_data/.
Configuration parameters
| Parameter | Description |
|---|---|
out_dir |
Output directory |
input_intensities |
Path to protein intensities file |
max_allowed_NAs_per_protein |
Maximum percentage of missing values per protein (default: 0.3) |
log_func_name |
Transformation funtion to apply to the data before model fitting: log (default), log10, log2, or null (if already log transformed) |
sample_annotation |
Path to sample annotations file (optional) |
index_col |
Column name containing protein IDs |
cov_used |
List of covariate column names from the annotation file (optional) |
find_q_method |
Method to determine latent dimension: OHT (default), gs, bs (binary search), or an integer |
pval_dist |
Distribution for p-value calculation: t (default) or gaussian |
likelihood |
gaussian (default: log intensities, MSE) or nb: the input is a matrix of raw counts (RNA-seq style, zeros are observations), the autoencoder is fitted with a negative-binomial likelihood (one dispersion per gene, learned jointly) and outliers are scored with the NB test on the fitted means, an OUTRIDER-style caller in Python. Use find_q_method: OHT or a fixed integer (not gs / bs) and lr: 1e-3 with a few thousand epochs; pval_dist does not apply |
n_epochs |
Number of training epochs (default: 100) |
checkpoint_path |
Path to save/load model checkpoint (optional) |
cohort_stability |
Run subsampling-based cohort stability analysis after the full cohort (default: false) |
cohort_stability_n_runs |
Number of subsampling iterations (default: 100) |
cohort_stability_min_runs |
Minimum iterations before optional runtime budget may stop (default: 30) |
cohort_stability_max_runtime_min |
Optional runtime budget in minutes (null = all iterations) |
cohort_stability_drop_fraction |
Fraction of samples removed per iteration (default: 0.1) |
cohort_stability_min_samples |
Minimum retained samples per iteration (default: 30) |
cohort_stability_seed |
Seed for subsampling and per-iteration models (defaults to seed) |
cohort_stability_require_oht |
Require find_q_method: "OHT" when stability is enabled (default: true) |
cohort_stability_save_iteration_files |
Save per-iteration wide and long outputs under each temp iteration directory (default: false) |
export_cooutlier_patient_similarity |
Export co-outlier patient stratification tables (default: true) |
z_threshold |
Absolute Z-score cutoff for up/down co-outlier bins (default: 3.0) |
cooutlier_min_anomalies |
Minimum aberrant proteins per sample for clustering/projections (default: 1) |
cooutlier_max_clusters |
Maximum k for agglomerative subpopulation search (default: 10) |
cooutlier_min_samples_for_clustering |
Minimum eligible samples for automatic k selection (default: 4) |
Optional cohort stability analysis (subsampling stability) measures sensitivity of outlier calls and effect sizes to cohort composition. This is not classical bootstrap (no sampling with replacement). Each iteration removes random samples, reruns the full OHT pipeline including preprocessing, and aggregates results into protrider_summary_bs.csv.
Requirements: cohort_stability: true, find_q_method: "OHT", and more than 30 samples. The standard full-cohort run always completes first.
find_q_method: "OHT"
cohort_stability: true
cohort_stability_n_runs: 100
cohort_stability_min_runs: 30
cohort_stability_drop_fraction: 0.1
cohort_stability_min_samples: 30
cohort_stability_seed: 42BS_N_RUNS_REQUESTED is the configured iteration count; BS_N_RUNS_COMPLETED is how many iterations actually ran (e.g. after a runtime budget). BS_N_OBSERVED, BS_N_MISSING, and BS_OBSERVED_FRACTION use completed runs as the denominator. PROTEIN_outlier_call_rate is outlier calls divided by observed iterations; PROTEIN_outlier_call_rate_all_runs uses completed runs. FC quantiles describe effect-size stability. The stability baseline always includes all sample–protein pairs from the full cohort, independent of report_all.
Example: PROTEIN_FC_full=0.50, PROTEIN_FC_q025=0.40, PROTEIN_FC_q975=0.60, PROTEIN_outlier_call_rate=0.87 means a ~50% FC in the full cohort, a 40–60% central interval under perturbation, and outlier calls in 87% of observed iterations.
The key output file is protrider_summary.csv, which contains outlier calls with p-values, z-scores, and fold changes for every sample–protein pair.
Output files
| File | Description |
|---|---|
protrider_summary.csv |
Long-format summary with outlier calls for all sample–protein pairs |
protrider_summary_bs.csv |
Cohort stability summary when cohort_stability: true and cohort size > 30 |
pvals.csv |
Two-sided p-values (samples × proteins) |
pvals_adj.csv |
BH/BY-adjusted p-values |
pvals_one_sided.csv |
Left-sided p-values |
zscores.csv |
Z-scores |
residuals.csv |
Model residuals (observed − predicted) |
log2fc.csv |
Log2 fold changes |
fc.csv |
Fold changes |
output.csv |
Autoencoder reconstructed values |
processed_input.csv |
Preprocessed input passed to the autoencoder |
additional_info.csv |
Model metadata (latent dimension, learning rate, loss) |
train_losses.csv |
Per-epoch training loss |
fit_parameters.csv |
Per-protein distribution fit parameters |
config.yaml |
Saved configuration for reproducibility |
latent_samples.csv |
Sample embeddings in the learned q-dimensional latent space; rows are samples, columns are latent dimensions |
latent_protein_loadings_svd.csv |
Protein loadings from SVD/OHT/PCA initialization; rows are proteins, columns are latent dimensions |
latent_protein_loadings_decoder.csv |
Learned decoder protein loadings for the linear autoencoder; rows are proteins, columns are latent dimensions |
patient_similarity.csv |
Sample × sample RBF similarity matrix from standardized latent embeddings |
patient_subpopulations.csv |
Per-sample subpopulation labels and clustering metadata |
patient_latent_pca.csv |
2D PCA coordinates of latent embeddings for visualization |
patient_latent_umap.csv |
2D UMAP coordinates of standardized latent embeddings (visualization only) |
patient_latent_tsne.csv |
2D t-SNE coordinates of standardized latent embeddings (visualization only) |
patient_similarity_info.csv |
Single-row run metadata (sigma, k, silhouette, UMAP/t-SNE status) |
cooutlier_patient_similarity.csv |
Sample × sample directional Jaccard similarity from extreme Z-scores |
cooutlier_patient_subpopulations.csv |
Per-sample co-outlier subpopulation labels and clustering metadata |
cooutlier_patient_burden.csv |
Per-sample counts of up/down/total aberrant proteins at z_threshold |
cooutlier_patient_pca.csv |
2D TruncatedSVD coordinates of sparse co-outlier profile (visualization) |
cooutlier_patient_umap.csv |
2D UMAP on co-outlier Jaccard distance (visualization) |
cooutlier_patient_tsne.csv |
2D t-SNE on co-outlier Jaccard distance (visualization) |
cooutlier_patient_info.csv |
Single-row co-outlier run metadata |
Latent-space outputs
PROTRIDER writes the files below when results are saved in wide format (including the default protrider run --config config.yaml workflow). They are not written for long format (protrider_summary.csv only).
| File | Shape | Meaning |
|---|---|---|
latent_samples.csv |
samples × q | Encoder latent embeddings (use for sample similarity / clustering) |
latent_protein_loadings_svd.csv |
proteins × q | Protein loadings from SVD/OHT/PCA init (if Vt is available) |
latent_protein_loadings_decoder.csv |
proteins × q | Linear decoder loadings (n_layers: 1 only) |
Latent samples vs residuals: residuals.csv is observed minus predicted intensities and may remove technical and biological signal the model already explained. latent_samples.csv is the encoder representation before residualization.
When decoder loadings are skipped: multilayer models (n_layers > 1) or presence/absence mode — you still get latent_samples.csv (and SVD loadings when available).
OHT with covariates: the CLI logs a warning that this combination has not been fully evaluated; the run still completes. SVD loadings use the centered protein matrix only (not covariates).
Downstream example (sample cosine similarity):
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
Z = pd.read_csv("output/latent_samples.csv", index_col=0)
sim = pd.DataFrame(
cosine_similarity(Z),
index=Z.index,
columns=Z.index,
)
sim.to_csv("output/sample_latent_cosine_similarity.csv")Patient similarity and subpopulations
When latent embeddings are available, PROTRIDER computes sample similarity and optional subpopulations automatically during run() and writes the patient files above in wide format.
Method (high level):
- Standardize latent dimensions (
StandardScaler) so no single axis dominates distances. - Pairwise Euclidean distances → RBF similarity (S_{ij} = \exp(-D_{ij}^2 / (2\sigma^2))) with (\sigma) = median of nonzero distances; diagonal set to 1.
- Subpopulations: Ward agglomerative clustering on standardized latents; choose k (2 … min(10, n−1)) by maximum silhouette score. Fewer than four samples → all assigned to
subpopulation_1. - PCA (2 components) on standardized latents for plotting.
- UMAP and t-SNE (2 components each) on the same standardized latents for nonlinear views.
PCA is deterministic and fast; UMAP and t-SNE provide nonlinear 2D views of the standardized latent space. UMAP uses umap-learn; t-SNE uses scikit-learn. These projections are for visualization only and do not affect patient similarity, clustering, p-values, residuals, or outlier calls.
Plots (optional; skipped with a warning if CSVs are missing):
uv run protrider plot --config config.yaml patient_similarity
uv run protrider plot --config config.yaml patient_latent_pca
uv run protrider plot --config config.yaml patient_latent_umap
uv run protrider plot --config config.yaml patient_latent_tsne
uv run protrider plot --config config.yaml cooutlier_patient_similarity
uv run protrider plot --config config.yaml cooutlier_patient_pca
uv run protrider plot --config config.yaml cooutlier_patient_umap
uv run protrider plot --config config.yaml cooutlier_patient_tsnePython API:
result.patient_similarity.similarity # square DataFrame
result.patient_similarity.subpopulations # per-sample labels
result.patient_similarity.pca_coordinates # PC1, PC2, subpopulation
result.patient_similarity.umap_coordinates # UMAP1, UMAP2, subpopulation
result.patient_similarity.tsne_coordinates # TSNE1, TSNE2, subpopulationPatient similarity is not computed from residuals or z-scores — only from latent_samples.
Co-outlier patient stratification
PROTRIDER can stratify patients by shared extreme Z-score profiles. The analysis binarizes in-memory result.df_Z (samples × proteins) into up- and down-regulated outlier sets using z_threshold. Pairwise similarity is a directional Jaccard index: two samples match only when the same protein is aberrant in the same direction (up/up or down/down). Non-aberrant proteins and opposite-direction pairs do not contribute, so the matrix reflects molecular error overlap rather than global proteomic background.
Latent vs co-outlier patient similarity:
| Latent patient similarity | Co-outlier patient similarity | |
|---|---|---|
| Input | Learned latent embeddings | Extreme Z-scores only |
| Captures | Broad sample structure before residualization | Shared up/down outlier patterns |
| Use case | General cohort structure | Rare-disease–like patients with shared aberrant proteins |
Method (high level):
- Sparse up/down indicators at
|Z| ≥ z_threshold. - Same-direction intersection counts via sparse matrix multiplication → directional Jaccard.
- Subpopulations: average-linkage agglomerative clustering on
1 − Jaccard(not Ward; precomputed non-Euclidean distance). Choose k by silhouette score. Low-burden samples (n_total < cooutlier_min_anomalies) are labeledunclassified_low_burden. - Projections: TruncatedSVD, UMAP, and t-SNE on the sparse co-outlier profile or precomputed distance (visualization only).
Plots (optional; skipped with a warning if CSVs are missing):
uv run protrider plot --config config.yaml cooutlier_patient_similarity
uv run protrider plot --config config.yaml cooutlier_patient_pca
uv run protrider plot --config config.yaml cooutlier_patient_umap
uv run protrider plot --config config.yaml cooutlier_patient_tsnePython API:
from protrider import compute_cooutlier_similarity
co = compute_cooutlier_similarity(result.df_Z, z_threshold=3.0)
co.similarity
co.subpopulations
co.pca_coordinates
co.umap_coordinates
co.tsne_coordinatesCo-outlier export is enabled by default (export_cooutlier_patient_similarity: true) and does not change p-values, Z-scores, residuals, latent exports, or latent-based patient similarity files. On large cohorts, set export_cooutlier_patient_similarity: false, export_patient_similarity: false, and/or export_latent_space: false in config.yaml for faster production runs (cohort stability iterations already disable these automatically).
Use these steps to verify a checkout on your machine (clone or pull main on your fork).
With uv (recommended; uses uv.lock):
uv sync
uv run protrider --helpOr with pip in your conda/venv:
pip install -e .
protrider --helpuv run pytest tests/ -qOptional focused runs:
uv run pytest tests/test_latent_space.py tests/test_patient_similarity.py tests/test_cooutlier_similarity.py -vFrom the repository root:
uv run protrider run --config config.yaml(config.yaml points at sample_data/ and writes to output/ by default.)
To force a fresh model fit (ignore an old checkpoint):
rm -f output/model.pt
uv run protrider run --config config.yamlAfter the run, confirm output/ contains core results and optional sample-level exports:
ls -1 output/latent_*.csv output/patient_*.csv output/cooutlier_patient_*.csv 2>/dev/nullExpected for the default linear config (n_layers: 1 in config.yaml):
output/latent_samples.csv,output/latent_protein_loadings_svd.csv,output/latent_protein_loadings_decoder.csvoutput/patient_similarity.csv,output/patient_subpopulations.csv, …output/cooutlier_patient_similarity.csv,output/cooutlier_patient_subpopulations.csv, …
Plots still work:
uv run protrider plot --config config.yaml allPython API:
import protrider
config = protrider.load_config("config.yaml")
result, model_info, fit_params, gs_result = protrider.run(config)
assert result.latent_space is not None
assert result.cooutlier_similarity is not None
result.save(config.out_dir, format="wide")Multilayer (n_layers: 2 in config): expect latent_samples.csv and SVD loadings, but no latent_protein_loadings_decoder.csv.
Run the pipeline:
protrider run --config config.yamlGenerate plots:
# All plots
protrider plot --config config.yaml all
# Individual plot types
protrider plot --config config.yaml pvals
protrider plot --config config.yaml aberrant_per_sample
protrider plot --config config.yaml training_loss
protrider plot --config config.yaml encoding_dim
# Expected vs observed for a specific protein
protrider plot --config config.yaml expected_vs_observed --protein_id <protein_id>
protrider plot --config config.yaml patient_similarity
protrider plot --config config.yaml patient_latent_pca
protrider plot --config config.yaml patient_latent_umap
protrider plot --config config.yaml patient_latent_tsne
protrider plot --config config.yaml cooutlier_patient_similarity
protrider plot --config config.yaml cooutlier_patient_pca
protrider plot --config config.yaml cooutlier_patient_umap
protrider plot --config config.yaml cooutlier_patient_tsneModel checkpointing
PROTRIDER automatically saves trained models and reuses them in subsequent runs, skipping retraining if a checkpoint exists. By default the model is saved to <out_dir>/model.pt.
To use a custom checkpoint location, set checkpoint_path in your config:
checkpoint_path: models/my_model.ptTo force retraining, delete the checkpoint file or point to a new path.
Python API
import protrider
config = protrider.ProtriderConfig(
out_dir='output/',
input_intensities='data/protein_intensities.csv',
sample_annotation='data/sample_annotations.csv',
index_col='protein_ID',
cov_used=['AGE', 'SEX'],
n_epochs=100,
)
# Run
result, model_info, fit_params, gs_result = protrider.run(config)
# Save results
result.save(config.out_dir, format='wide') # individual CSV files
result.save(config.out_dir, format='long') # protrider_summary.csv
model_info.save(config.out_dir)
config.save(config.out_dir)
# Generate plots (omit out_dir to get plot objects without saving)
model_info.plot_training_loss(config.out_dir)
result.plot_aberrant_per_sample(config.out_dir)
hist_plot, qq_plot = result.plot_pvals(config.out_dir)
result.plot_expected_vs_observed('protein_123', config.out_dir)
# Access results as DataFrames
result.df_pvals # p-values
result.df_pvals_adj # adjusted p-values
result.df_Z # z-scores
result.df_res # residuals
result.log2fc # log2 fold changes
result.fc # fold changes
# Latent-space objects (also written by result.save(..., format="wide"))
Z_samples = result.latent_space.samples
protein_loadings_svd = result.latent_space.protein_loadings_svd
protein_loadings_decoder = result.latent_space.protein_loadings_decoder # None for multilayer models
# Patient similarity (when latent_space is available)
patient_sim = result.patient_similarity.similarity
patient_subpops = result.patient_similarity.subpopulations
patient_pca = result.patient_similarity.pca_coordinates
# Co-outlier stratification (from Z-scores; written when export_cooutlier_patient_similarity is true)
co = result.cooutlier_similarity
co_sim = co.similarity
co_subpops = co.subpopulations
co_pca = co.pca_coordinatesThis project is licensed under the MIT License.
If you use PROTRIDER, please cite:
@article{10.1093/bioinformatics/btaf628,
author = {Klaproth-Andrade, Daniela and Scheller, Ines F and Tsitsiridis, Georgios and Loipfinger, Stefan and Mertes, Christian and Smirnov, Dmitrii and Prokisch, Holger and Yépez, Vicente A and Gagneur, Julien},
title = {PROTRIDER: Protein abundance outlier detection from mass spectrometry-based proteomics data with a conditional autoencoder},
journal = {Bioinformatics},
pages = {btaf628},
year = {2025},
month = {11},
issn = {1367-4811},
doi = {10.1093/bioinformatics/btaf628},
url = {https://doi.org/10.1093/bioinformatics/btaf628},
}