Repository navigation
Add SumRank across studies, with permutations and held-out prediction - #60
Merged
Merged
Conversation
SumRank ranks each gene's differential expression within every study of a CubeCollection and sums its best ranks, with Irwin-Hall p-values and a null pooled over permutations that re-run each study's limma analysis. Held-out prediction reports each study's AUC from genes chosen in the other studies, by SumRank and by meta-analysis. plot_sumrank and plot_held_out_auc draw the authors' Manhattan plot and the AUC by study. Checked against the authors' R code (Apache-2.0), mpmath, scipy and scikit-learn (validation/sumrank.py: 23 checks, none failed).
parashardhapola
force-pushed
the
50-sumrank
branch
from
October 26, 2026 21:11
941b81f to
98e2e49
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Most genes that one single-cell study finds changed are not found by the next, and a meta-analysis that weighs studies by precision can pass a gene on one or two studies alone. SumRank (Nakatsuka et al. 2025) asks instead that a gene rank high in most studies: each study ranks its genes, and a gene's best normalized ranks are summed across the studies. This adds SumRank on plain arrays and on the studies of a
CubeCollection, with Irwin-Hall p-values and p-values from permutations that re-run each study's analysis; the paper's measure of replication, the AUC of cases against controls in each held-out study scored by genes chosen from the others (by SumRank and, for comparison, by the meta-analysis already built); and the two figures. It is checked against the authors' own R code, run as they publish it, mpmath, a complete enumeration of permutations and scikit-learn.Changes
cytepool.sumrank.sumrank(statistics, *, proportion_of_studies, null_statistics): studies x genes signed statistics (NaN where a study did not test a gene), and optionally the statistics of permuted studies; returnsSumRankFit: the statistics up and down, Irwin-Hall p-values, permutation p-values, the normalized ranks, and the numbers of studies, ranks summed and null statistics.cytepool.sumrank.differential_expression_sumrank(collection, results, group, contrast, *, proportion_of_studies, n_permutations, permute, rng): SumRank of one cell type and contrast from each study'slimma_voom,limma_trendordream_voomresult, read throughalign_study_results; withn_permutations, permutes the design variablepermuteamong the samples of each study's fit and re-runs its analysis; returnsSumRankResult(a table of the genes, a table of the studies, settings, provenance). Warns when fewer than all studies are summed without permutations.cytepool.held_out_prediction.held_out_prediction(collection, results, contrast, variable, case, control, *, groups, n_genes, proportion_of_studies): leaves each study out, choosesn_genesgenes up and down per cell type from the others by SumRank and by a REML meta-analysis with Knapp-Hartung, scores every case and control by UCell's rank score, and returnsHeldOutPredictionwith the tablesauc(by study and method),scoresandgenes.cytepool.plotting.plot_sumrank: the authors' Manhattan plot, the -log10 p-value of every gene in alphabetical order, the genes that pass coloured and named, with the threshold where they draw it;cytepool.plotting.plot_held_out_auc: the AUC of every held-out study by method, with the mean of each.cytepool/_study_statistics.py(private): each study's signed statistics, log2 fold changes and standard errors as arrays, and the number of studies summed.sumrankandheld_out_prediction; a row of the capability matrix; five references (Irwin 1927, Hall 1927, Andreatta and Carmona 2021, Hanley and McNeil 1982, Robin et al. 2011; DOIs checked against Crossref) cited on the Bibliography page; the Validation page (row, totals, section, timing, how to run); the README's status table; the Overview.Design notes
The authors' code (https://github.com/nathan-nakatsuka/scRNA_Reproducibility) is under the Apache-2.0 licence, so it was read, and its conventions settle what the paper leaves open; no code was copied.
THIRD_PARTY_NOTICES.mdneeds an entry for it, proposed at the end.What the paper and the authors' code specify, and CytePool follows:
rank); u = (r - 1) / (G - 1); the m smallest of a gene's k normalized ranks are summed, m = floor(p k) for the proportion p of the studies; a sum above m / 2 is set to m / 2. Genes down are tested by testing controls against cases: here their normalized ranks are 1 - u, the same.GetCommonGenes), and a study without the cell type is left out, k counting the others.What it leaves open, and how it is settled here:
numpy.random.Generatorpermutation by permutation and study by study, and re-runlimma_voomorlimma_trendfrom the design and settings each result records, on the study's aligned cube; the result's cube fingerprint and settings are checked against the re-run. A permutation's statistics use the genes its analyses tested. Designs with random effects (dream) are not permuted: their samples are not exchangeable.limma_voomfor 40 samples and 10,000 genes (0.14 s withlimma_trend), so 100 permutations of 20 studies take about 7 minutes on a laptop; memory is that of one analysis and a few arrays of the genes. Pooling over genes, 100 permutations of 10,000 genes give p-values down to 1e-6. Held-out prediction of 10 studies, 2 cell types and 10,000 genes takes 1.4 s.Deliberate differences
dirwin.hall, the Irwin-Hall density, at the sum, which is not a probability and is constant for m = 1. Both are monotone in the sum for m >= 2, so the permutation p-values are unaffected.direction = "auto"picks the direction per study, which lifts a reversed score above 0.5.Validation
validation/sumrank.py, 23 checks: 13 pass, 1 deliberate difference, 9 information, none failed (44.9 s, 399 MiB peak). It downloadsSumRank.R,CalibratePValueswithPermutations.RandMakingManhattanPlots.Rat commit 46392f66 (SHA-256 checked) and runs them as published, withlibrarystubbed (they load unifed only fordirwin.hall) anddirwin.hallreplaced by the identity, so that their tables hold the capped sums; for the figure,plot,ablineandtextrecord whatMakeManhattanPlotdraws. Reference: R 4.4.3, the authors' code, mpmath 1.3.0, scipy 1.18.1, scikit-learn 1.9.1.sumrank's statisticsSumRankSumRank,CalibratePValueswithPermutationsCalibratePValueswithPermutationsrankdata, scikit-learn'sroc_auc_score, the authors'SumRankplot_sumrank: every gene's -log10 p-value in alphabetical order, the threshold line (theirs 1e-5 higher) and the genes namedMakeManhattanPloton the same p-valuesTests
tests/test_sumrank.py(43) andtests/test_held_out_prediction.py(19): 62 tests, 2.5 s warm, 73 s cold with an empty compile cache. They compare with the authors' code (fixtures intests/data/sumrank/authors.npz, 41 KB: tied p-values; 4 studies with 20 permutations, whose permutation p-values must equal the count over the authors' null exactly); with values derived by hand (two studies with ties and a gene one study lacks, one of two studies summed, the four permutations of two three-gene studies, a permutation that tested fewer genes, infinite statistics, one study); with closed forms of the Irwin-Hall distribution (x^n / n!, symmetry, F_n(n/2) = 1/2); and with invariants: the order of studies and genes, negated statistics swapping up and down, a monotone transform of a study, explicit permutations analysed by hand against the driver, seeds reproducing permutations and threads not changing them, the held-out study's own results choosing none of its genes, and swapping cases and controls giving 1 - AUC. Held-out scores and AUC are recomputed with scipy (rankdata,mannwhitneyu), and the chosen genes withsumrankandmeta_analysison the other studies. Messages, the refusal of dream for permutations, the check of a result from another cube, the figures' data, and the masked-input inventory (38 tests) are covered.Checks: the full suite on master, 4,816 passed, 18 skipped, also with bounds checks and with the rounding changed (
OPENBLAS_CORETYPE=Sandybridge, 4 threads,NUMBA_CPU_NAME=generic, fresh cache); Python 3.14: 4,837 passed; Python 3.15: 4,731 passed, 107 skipped;ruff checkandruff format --checkon cytepool, tests, validation and docs clean;mypy cytepoolclean;make -C docs apiandmake -C docs html(Node.js 24) build;tests/test_documentation.py74 passed.THIRD_PARTY_NOTICES.mdgains a SumRank entry under "Adapted material": the conventionstaken from the authors' Apache-2.0 code, file by file, and that no code is copied.