Getting started with presto
getting-started.Rmdpresto runs the Wilcoxon rank-sum test and computes the
auROC statistic quickly enough to be used as a routine marker-finding
step on whole-genome, hundred-thousand-cell single-cell experiments.
Demo data
This vignette uses CD8 T cells from human colon tissue published by
Thomas et
al., Nature Medicine 2024 (GSE206299).
load_ircolitis_cd8() downloads the 121 MB
.h5ad.gz file on first use, caches it under
tools::R_user_dir("presto", "cache"), and parses it with
rhdf5.
library(presto)
library(Matrix)
library(dplyr)
d <- load_ircolitis_cd8(verbose = FALSE)
dim(d$counts)
#> [1] 28165 25341d$counts is a 28,165 × 25,341 sparse matrix of UMI
counts (genes × cells). d$obs carries cell metadata,
including a cluster column we will use to identify
markers.
table(d$obs$cluster)
#>
#> 1 2 3 4 5 6 7 8 9
#> 8380 5115 2604 2246 2235 2049 1860 655 197Quick start
The simplest call passes a feature-by-cell matrix and a vector of group labels:
res <- wilcoxauc(d$counts, d$obs$cluster)
head(res)
#> feature group avgExpr logFC statistic auc pval padj pct_in
#> 1 ENSG00000243485|MIR1302-2HG 1 0.000000 0.000000 71066590 0.500 1.000000 1.00000 0.0000
#> 2 ENSG00000238009|AL627309.1 1 0.000239 -0.000233 71050031 0.500 0.379630 0.67361 0.0239
#> 3 ENSG00000241599|AL627309.4 1 0.000000 0.000000 71066590 0.500 1.000000 1.00000 0.0000
#> 4 ENSG00000235146|AC114498.1 1 0.000000 0.000000 71066590 0.500 1.000000 1.00000 0.0000
#> 5 ENSG00000237491|AL669831.5 1 0.053938 0.011016 71757724 0.505 0.000418 0.00187 5.1074
#> 6 ENSG00000177757|FAM87B 1 0.000000 0.000000 71066590 0.500 1.000000 1.00000 0.0000
#> pct_out
#> 1 0.0000
#> 2 0.0472
#> 3 0.0000
#> 4 0.0000
#> 5 4.1389
#> 6 0.0000Each row reports one (gene, group) test. Rows are returned for every gene × cluster combination, comparing observations in that cluster against all other observations.
Result columns
| column | description |
|---|---|
feature |
name of the feature (gene) |
group |
name of the group / cluster |
avgExpr |
mean expression of the feature in the group |
logFC |
log fold change between in-group vs out-of-group observations |
statistic |
Wilcoxon rank-sum U statistic |
auc |
area under the ROC curve |
pval |
nominal p-value, two-sided Gaussian approximation of U |
padj |
Benjamini-Hochberg adjusted p-value |
pct_in |
percent of in-group cells with non-zero expression |
pct_out |
percent of out-of-group cells with non-zero expression |
Top markers per cluster
top_markers() extracts the most distinguishing features
per group. Use auc_min, padj_max,
pct_in_min, and pct_out_max to filter.
top_markers(res, n = 5, auc_min = 0.6, padj_max = 1e-3)
#> # A tibble: 5 × 10
#> rank `1` `2` `3` `4` `5` `6` `7` `8` `9`
#> <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1 ENSG00000198727|MT-CYB ENSG00000153563|CD8A ENSG000… ENSG… ENSG… ENSG… ENSG… ENSG… ENSG…
#> 2 2 ENSG00000117632|STMN1 ENSG00000142669|SH3BGRL3 ENSG000… ENSG… ENSG… ENSG… ENSG… ENSG… ENSG…
#> 3 3 ENSG00000128951|DUT ENSG00000196154|S100A4 ENSG000… ENSG… ENSG… ENSG… ENSG… ENSG… ENSG…
#> 4 4 ENSG00000198804|MT-CO1 ENSG00000116824|CD2 ENSG000… ENSG… ENSG… ENSG… ENSG… ENSG… ENSG…
#> 5 5 ENSG00000198938|MT-CO3 ENSG00000167286|CD3D ENSG000… ENSG… ENSG… ENSG… ENSG… ENSG… ENSG…The gene identifiers are the verbatim row names from the input matrix
(ENSG…|SYMBOL). To plot just the symbol portion, split at
|:
top5 <- top_markers(res, n = 5, auc_min = 0.6, padj_max = 1e-3)
top5 %>%
dplyr::mutate(across(-rank, ~ sub(".*\\|", "", .x)))
#> # A tibble: 5 × 10
#> rank `1` `2` `3` `4` `5` `6` `7` `8` `9`
#> <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1 MT-CYB CD8A GZMK GAPDH IL7R ACTG1 TYROBP TNFRSF4 JCHAIN
#> 2 2 STMN1 SH3BGRL3 CD27 GZMA RPS12 CCL5 FCER1G SRGN IGHA1
#> 3 3 DUT S100A4 CST7 CD7 S100A4 TMSB4X TRDC ITGB2 IGKC
#> 4 4 MT-CO1 CD2 ITGB2 TPI1 LTB CD52 TNFRSF18 NFKBIA IGLC2
#> 5 5 MT-CO3 CD3D GZMH GZMB RPS14 SH3BGRL3 GSTP1 CTLA4 IGLC3Restricting to a subset of groups
Use groups_use to compare only a subset of groups
against each other:
res_12 <- wilcoxauc(d$counts, d$obs$cluster, groups_use = c("1", "2"))
top_markers(res_12, n = 10, auc_min = 0.6, padj_max = 1e-3)
#> # A tibble: 10 × 3
#> rank `1` `2`
#> <int> <chr> <chr>
#> 1 1 ENSG00000198727|MT-CYB ENSG00000153563|CD8A
#> 2 2 ENSG00000198938|MT-CO3 ENSG00000116824|CD2
#> 3 3 ENSG00000198886|MT-ND4 ENSG00000196154|S100A4
#> 4 4 ENSG00000198712|MT-CO2 ENSG00000111796|KLRB1
#> 5 5 ENSG00000198804|MT-CO1 ENSG00000197956|S100A6
#> 6 6 ENSG00000117632|STMN1 ENSG00000142669|SH3BGRL3
#> 7 7 ENSG00000212907|MT-ND4L ENSG00000137078|SIT1
#> 8 8 ENSG00000198888|MT-ND1 ENSG00000166710|B2M
#> 9 9 ENSG00000128951|DUT ENSG00000213658|LAT
#> 10 10 ENSG00000164104|HMGB2 ENSG00000197540|GZMMSeurat and SingleCellExperiment
wilcoxauc() dispatches on the input class. For Seurat or
SingleCellExperiment objects, pass the object and the name of the
metadata column that defines the groups:
# Seurat
wilcoxauc(seurat_object, group_by = "cluster")
# SingleCellExperiment
wilcoxauc(sce_object, group_by = "cluster")For the full set of arguments (assay selection, layer, etc.), see
?wilcoxauc.
Notes on input types
wilcoxauc() accepts dense matrices, sparse
dgCMatrix inputs, and data.frames. Sparse
input is faster and uses far less memory on single-cell data. The matrix
should be features × observations (rows are genes,
columns are cells).
Session info
sessionInfo()
#> R version 4.5.2 (2025-10-31)
#> Platform: aarch64-apple-darwin20
#> Running under: macOS Sequoia 15.6.1
#>
#> Matrix products: default
#> BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
#> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
#>
#> locale:
#> [1] en_US/en_US/en_US/C/en_US/en_US
#>
#> time zone: America/New_York
#> tzcode source: internal
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] dplyr_1.2.1 Matrix_1.7-4 presto_1.0.0 knitr_1.51 ggplot2_4.0.2
#>
#> loaded via a namespace (and not attached):
#> [1] vctrs_0.7.2 cli_3.6.5 rlang_1.1.7 xfun_0.56
#> [5] otel_0.2.0 purrr_1.2.1 generics_0.1.4 S7_0.2.1
#> [9] data.table_1.18.2.1 glue_1.8.0 scales_1.4.0 grid_4.5.2
#> [13] evaluate_1.0.5 tibble_3.3.1 Rhdf5lib_1.32.0 lifecycle_1.0.5
#> [17] compiler_4.5.2 RColorBrewer_1.1-3 rhdf5filters_1.22.0 Rcpp_1.1.1
#> [21] pkgconfig_2.0.3 tidyr_1.3.2 rhdf5_2.54.1 lattice_0.22-7
#> [25] farver_2.1.2 R6_2.6.1 utf8_1.2.6 dichromat_2.0-0.1
#> [29] tidyselect_1.2.1 pillar_1.11.1 magrittr_2.0.5 tools_4.5.2
#> [33] withr_3.0.2 gtable_0.3.6