Skip to content

Prediction reports: training-set membership, novelty and conformal intervals (v4.4.0) - #118

Open
RobbinBouwmeester wants to merge 2 commits into
feat/multihead-calibrationfrom
feat/prediction-report
Open

Prediction reports: training-set membership, novelty and conformal intervals (v4.4.0)#118
RobbinBouwmeester wants to merge 2 commits into
feat/multihead-calibrationfrom
feat/prediction-report

Conversation

@RobbinBouwmeester

Copy link
Copy Markdown
Member

Stacked on #117 (the report reuses MultiHeadRidgeCalibration and the uses_all_heads flag); the diff shown here is the report feature only. Retarget to main once #117 is merged.

What

prediction_report(psm_list, psm_list_reference=..., coverage=0.90, training_index=...) returns predictions together with what a bare number cannot say, one row per PSM:

column meaning
predicted_rt calibrated prediction, as predict_and_calibrate
ci_lower, ci_upper conformal interval at the requested coverage
in_reference exact peptidoform match in the calibration reference
dist_to_reference Levenshtein distance to the closest reference sequence
in_training * exact match anywhere in the 10,105,640-peptidoform corpus behind the bundled multitask model
in_selected_heads_training * match within the training sets of the setups the calibration selected (all 80 for the multi-head calibration, the single best head otherwise)
dist_to_training * distance to the closest training sequence, exact to 10 edits, capped beyond

* with a TrainingIndex, a ~400 MB memory-mapped artifact (sorted key hashes, per-setup membership CSR, 6.16 M unique sequences) built offline from the training cache by build_training_index.py in the research repo. The report works without it. Hosting to be decided (HF hub?).

The interval

Cross-fitted split-conformal on the reference: five folds, each predicted by a calibration fitted on the other four, half-width = finite-sample quantile of those honest |residuals| per predicted-RT bin (peak width varies along a gradient). No retraining, works for any model and calibration, finite-sample marginal coverage guarantee. Chosen over quantile regression (pinball) for exactly those reasons.

Validated on the eight held-out PRIDE setups (Figure 1b corpus), nominal 90 %:

  • coverage per setup 0.88-0.97 (median 0.91); at nominal 80 %: median 0.80; at 95 %: median 0.96;
  • width 4-10 % of the gradient on well-behaved setups, honestly wide where predictions are bad (35 % on the wheat-gluten out-of-domain setup, 79 % on the run that pools fractions);
  • distance-scaled widths were tested and rejected: error is flat in edit distance (Figure 2), so they only overcover.

End-to-end through this API on three held-out setups: coverage@90 = 0.914 / 0.898 / 0.974, and the membership columns behave (PXD079927: 60 % of test peptidoforms in the corpus but only 1.2 % in the 80 selected setups; PXD081880: 100 % / 95 %).

Canonical keys

canonical_peptidoform_key reproduces the corpus key format (peprec positions, U:<unimod id>, lowercased unmapped names, position-sorted, charge ignored) — verified against real corpus keys, including modified ones.

Verification

  • 155 tests pass; 14 new in tests/test_report.py (key format, interval coverage / adaptivity / thin-bin fallback on synthetic data, index membership global and per-setup, capped distances, non-index directory refused, report end-to-end with and without index, pre-fitted calibration refused, multi-head head listing).
  • ruff check / format clean on the new files.
  • New dependency: rapidfuzz (pure wheel).
  • Version 4.4.0, CHANGELOG and usage docs updated.

🤖 Generated with Claude Code

A prediction is a number with no way to tell whether the model has seen the
peptidoform, merely something like it, or nothing like it, and no statement of
how far off it may be. prediction_report answers all three per PSM.

Membership and novelty: exact match against the calibration reference and the
Levenshtein distance to its closest sequence, always; with a TrainingIndex also
exact match against the 10,105,640-peptidoform corpus behind the bundled
multitask model, membership within the training sets of the setups the
calibration selected, and the distance to the closest training sequence (exact
to ten edits, capped beyond; the error is flat in this distance, so the cap
costs nothing but keeps the search fast). Canonical keys reproduce the corpus
format: peprec positions, Unimod accessions, lowercased unmapped names.

Uncertainty: cross-fitted split-conformal intervals on the reference. Each
reference fold is predicted by a calibration fitted on the other folds and the
half-width is a finite-sample quantile of those honest residuals per
predicted-RT bin. On eight held-out PRIDE setups the 90 % interval covered 0.88
to 0.97 per setup (median 0.91), 4 % of the gradient wide on well-behaved setups
and honestly wide (79 %) on a run that pools fractions. Chosen over quantile
regression because it needs no retraining and carries a finite-sample guarantee;
coverage is marginal, not per-peptide.

The TrainingIndex (~400 MB: sorted key hashes, per-setup membership CSR, unique
sequences) is built offline from the training cache and distributed separately;
the report works without it and then carries the reference columns only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@RobbinBouwmeester

Copy link
Copy Markdown
Member Author

Index size addressed in 39b621e: the artifact is now a single 105 MB .dlcidx file instead of a 400 MB directory. Stdlib LZMA zip; the interesting part is the hashes — random bits compress 1.4x at best, so they are truncated to 40 bits in a bucketed layout instead (2^24 bucket counts + 16-bit remainders, ~26 MB), costing a false positive about once per 100,000 membership queries, which a provenance flag can afford. Setup lists 2.8x, sorted sequences 3.1x, CSR pointers stored as row lengths 5.3x. Loads in about a second, answers bit-identical to the raw form, and every index test now runs against both formats.

The directory form was 400 MB across seven files, most of it uncompressed
structure: raw 64-bit hashes, int64 pointers, plain text. The packed .dlcidx is
a stdlib LZMA zip that exploits what each component actually is. Sorted hashes
are truncated to 40 bits and stored as 2^24 bucket counts plus 16-bit
remainders, which costs a false positive about once per 100,000 membership
queries and nothing else; a provenance flag does not need exactness beyond
that. CSR pointers become uint16 row lengths (5x under LZMA), the setup lists
and the sorted sequences compress 2.8x and 3.1x. Loading rebuilds the sorted
hash array in about a second; answers are bit-identical to the directory form
on membership, per-setup membership and distances, which the tests now check by
running every index test against both formats.

TrainingIndex reads both forms; the builder emits both.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant