![]() |
OpenMS
|
Percolator-RESET: semi-supervised rescoring with FDR control at the peptide (stem) level. More...
#include <OpenMS/ANALYSIS/ID/PercolatorReset.h>
Classes | |
| struct | AuditFeature |
| struct | Input |
| Rows: one per PSM (all hits of all spectra), in any order. More... | |
| struct | Options |
| struct | Output |
| struct | Stem |
| One considered or dropped stem. More... | |
Public Types | |
| enum class | Role : int { TARGET = 0 , ESTIMATING_DECOY = 1 , TRAINING_DECOY = 2 } |
| Role of a row's stem (decoy stems by their coin) More... | |
Static Public Member Functions | |
| static Output | run (const Input &input, const Options &options) |
| Runs RESET; throws Exception::InvalidValue on malformed input or without decoy stems. | |
| static std::vector< double > | seqStepQValues (const std::vector< bool > &is_decoy, double factor, double plus_one) |
| static bool | isTrainingDecoy (std::uint64_t salt, const std::string &stem) |
| The coin of a decoy stem: true = training decoy. Exposed for tests. | |
Percolator-RESET: semi-supervised rescoring with FDR control at the peptide (stem) level.
Implements the single-decoy RESET procedure of Freestone, Käll, Noble and Keich (J Proteome Res 2025, "How to train a postprocessor ... while maintaining control of the FDR"; theory: Freestone, Noble and Keich, arXiv:2411.15771), as Percolator 3.07+ ('–reset-algorithm') and the authors' Python implementation do:
The stem-level q-values are the procedure's FDR-controlled output. Everything at PSM level is heuristic (see Output::psm_q_values).
Two-decoy mode (Options::decoy_databases = 2; the paper's two-decoy mode, Algorithms 3a/4 there and the authors' Python with mult = 2): the search ran against the targets and two decoy databases of the same construction, so the PSM-level competition of step 1 is the best of three and a null stem is a target, a decoy of set 1 or a decoy of set 2 with probability 1/3 each. The coin of step 3 is drawn for every decoy stem of either set, as in single-decoy mode. Then each training decoy faces on average two null pseudo-targets (one estimating decoy, one incorrect target): the positive set and the cross-validation use SeqStep+ at c = 2/3 (factor 2 instead of 3), and the final ranking FDP = (D_est + 1) / max(T, 1) (c = 1/2, factor 1 instead of 2). Input::decoy_set tells the two sets apart; it only checks that both are present (Output::decoy_stems_second_set: a set that never wins means the database had no second decoy set, and the factors would be wrong) and counts shared decoy sequences: a stem whose decoy rows (all rows of its sequence, also competition losers) come from both sets is one decoy for its hypotheses, which win as a decoy with probability 1/2 instead of 2/3; such stems count twice in the positive-set and final estimates (training and estimating decoy 1/4 each against 1/2 for the null target), and the final estimate's offset is then the largest weight, (sum of the weights + 2) / max(T, 1) (with + 1, a block of shared null hypotheses is anti-conservative). The detection needs the complete protein evidence of every decoy hit (all proteins that contain its sequence, as ProSE reports them): a shared sequence reported with the proteins of one set only counts once and its hypotheses are then under-estimated. Equal shares do not prove exchangeability: the two sets must be built so that a null hypothesis really has two independent decoys of the target's distribution (e.g. no sequences shared between the sets, the same multiplicity of sequences in both).
Feature-symmetry audit (Options::audit): before training, the training decoys are compared with an unlabelled null proxy, the pseudo-targets below the median search engine score of the training decoys (the training decoys are restricted to the same score range; the lowest third of the targets would be mostly correct targets in runs with many identifications). Per feature the AUC (Mann-Whitney) and the two-sample Kolmogorov-Smirnov statistic are reported, and a cross-fitted logistic regression on all features gives a multivariate AUC. Features with |AUC - 0.5| > 0.05, and the set if the multivariate AUC exceeds 0.55, are flagged; flags are reported, nothing is dropped. The null proxy holds the estimating decoys, too (about a third of its nulls), which attenuates real asymmetries by about a third.
| struct OpenMS::PercolatorReset::AuditFeature |
| struct OpenMS::PercolatorReset::Options |
| Class Members | ||
|---|---|---|
| bool | audit = false |
run the feature-symmetry audit |
| vector< double > | c_values = {0.1, 1.0, 10.0} | grid for C+ and C- (all pairs) |
| int | decoy_databases = 1 | decoy databases searched: 1 (default) or 2 (two-decoy mode, see the class description; needs Input::decoy_set) |
| int | iterations = 25 | training rounds (5 in the paper; they do not converge on DIA data) |
| string | learner = "svm" |
"svm" (linear) or "mlp" (small MLP ensemble, experimental) |
| bool | mlp_crossfit = true |
MLP cross-fitting: the stems (folds fixed by a hash of salt and sequence) are scored by the ensemble of the chosen C pair that did not train on their fold, in every round and at the end (no final fit); otherwise one final ensemble trained on all training stems scores everything, which ranks the training decoys it trained on too low |
| int | mlp_epochs = 30 |
MLP training epochs (the first round, or every round without warm starts) |
| int | mlp_hidden = 16 | MLP hidden units (two hidden layers) |
| int | mlp_members = 8 | MLP ensemble size. |
| int | mlp_norm_min_decoys = 1000 |
MLP cross-fitting: the fold ensembles' scores are normalized (as Percolator's folds: the fold's score at train_fdr against its training decoys -> 0, its median training decoy -> -1) only if every fold has at least this many training decoys (0 = always) |
| int | mlp_warm_epochs = 3 |
MLP warm starts: > 0 = the networks of each cross-validation task and of the final model continue from the previous round for this many epochs (a stem keeps its fold over the rounds); 0 = trained afresh every round |
| string | representative = "model" |
"model" (default): after each round a stem is represented by its PSM with the best score under the new model; "search": by its PSM with the best search engine score (the paper). With "model" masking holds, but the FDR also needs null targets and decoys to be exchangeable over their whole PSM collections, including their sizes (a null target with many more PSMs than a decoy gains from the maximum); entrapment validation decides. |
| optional< uint64_t > | salt | coin salt (never pick the best of several salts); unset = a fresh random salt, recorded in Output::salt |
| int | threads = 1 | threads for the cross-validation solves |
| double | train_fdr = 0.01 | FDR for the positive set and for the cross-validation counts. |
| vector< string > | zero_features = {"enzInt"} | features set to 0 (target-biased, as in the paper) |
| struct OpenMS::PercolatorReset::Output |
| Class Members | ||
|---|---|---|
| vector< AuditFeature > | audit | |
| Size | audit_decoys = 0 | |
| bool | audit_flagged = false | |
| double | audit_multivariate_auc = 0.5 | |
| Size | audit_proxy = 0 |
audit group sizes (training decoys, null proxy) |
| double | audit_proxy_ratio = 0.0 | null-proxy stems per training decoy in the audit (about 3 if all null) |
| Size | decoy_stems = 0 | |
| Size | decoy_stems_both_sets = 0 | |
| Size | decoy_stems_second_set = 0 |
two-decoy mode: considered decoy stems whose representative is a decoy of the second set (about half of decoy_stems if the two sets are exchangeable), and those whose representative is in both sets (Input::decoy_set 3; should be rare: a decoy sequence shared by the sets is one decoy, not two, for its spectra) |
| Size | discoveries_1pct = 0 | target stems with q <= 0.01 |
| Size | estimating_decoys = 0 | |
| string | learner | |
| string | learner_settings | learner "mlp": its settings (for reports); empty for "svm" |
| vector< double > | psm_peps |
per row, heuristic PSM-level posterior error probability: f p / (1 - p) (at most 1; f = 2, or 1 in two-decoy mode, where shared decoy stems count twice), with p the estimating-decoy fraction of the ranked PSMs by isotonic (antitonic in score) regression. 1 where q is 1 by definition (other hits, training decoys). |
| vector< double > | psm_q_values |
per row, heuristic PSM-level q-value: per spectrum, the hit with the best search engine score is the PSM (the competition that selects the stems' PSMs, so a stem's representative is always reported); PSMs of training-decoy sequences (decoy rows whose sequence's coin is "training") are dropped, and the remaining PSMs (targets, estimating decoys) get q = min over lower ranks of 2 (D_est + 1) / max(T, 1) (two-decoy mode: (D_est + 1) / max(T, 1); with shared decoy stems, as the final ranking, (sum of the decoy weights + 2) / max(T, 1)). 1 for the other hits and for training decoys. Not FDR-controlled (multiplicity of PSMs per peptide). |
| vector< Role > | roles | per row: role of the row's stem |
| vector< string > | rounds | training summary per round: chosen C+, C-, held-out discoveries, positives |
| uint64_t | salt = 0 | the effective salt and the learner (for reports) |
| vector< double > | scores | per row: score of the final model (all rows, also those that lost a competition) |
| vector< double > | stem_q_values | per row: q-value of the row's stem (Stem::q_value) |
| vector< Stem > | stems | all stems (considered or not) |
| Size | target_stems = 0 | |
| Size | training_decoys = 0 | |
| vector< string > | used_features | features the learner used (non-constant, not zeroed) |
| vector< double > | weights | linear learner: raw-feature weights of the final model, bias last |
| struct OpenMS::PercolatorReset::Stem |
One considered or dropped stem.
| Class Members | ||
|---|---|---|
| bool | considered = false | ranked (always true: PSM-only protocol; kept for the stem table format) |
| bool | decoy = false |
label of the search-score representative; fixed (masking) even if representative "model" later picks a PSM of the other label |
| double | q_value = 1.0 | RESET q-value (1 for training decoys and stems not considered) |
| Size | representative = 0 | row of the stem's best PSM (by search engine score) |
| Role | role = Role::TARGET | |
| double | score = 0.0 | final model score of the representative |
| double | search_score = 0.0 | search engine score of the representative |
| string | stem | unmodified sequence |
|
strong |
|
static |
The coin of a decoy stem: true = training decoy. Exposed for tests.
Runs RESET; throws Exception::InvalidValue on malformed input or without decoy stems.
|
static |
SeqStep(+) q-values of a ranked list (best first): fdp_k = min(1, factor (D_k + plus_one) / max(T_k, 1)), q = minimum of fdp over ranks >= k. is_decoy per rank. Exposed for tests.