Skip to content

Understanding Your Search Results: PSM, Peptide, and Protein Tables

Every Tesorai search produces three linked result tables, each at a different level of granularity:

TableOne row per…Answers the question…
quantified_psm_fdrone MS/MS spectrum matched to a peptide”What did this spectrum look like, and how confident are we?”
pep_fdrone peptide sequence (per file)“Which distinct peptides did we confidently identify?”
quantified_protein_fdrone protein group (per file)“How much of each protein was in the sample?”

They form a pipeline: raw spectra are matched to peptides (PSMs) → the best match per peptide is kept (peptides) → peptides are grouped into the proteins they came from and their signal is summed up (proteins). Below, we walk through each table, then cover the two topics that generate the most questions: how proteins are inferred from peptides, and what the different intensity columns mean.

What it is: the most granular table. A PSM (Peptide-Spectrum Match) is a single fragmentation spectrum (MS/MS scan) paired with the peptide sequence Tesorai believes produced it. If the same peptide is fragmented in three different scans, you get three rows.

How it’s generated: Tesorai’s search engine scores every candidate spectrum-to-peptide match. Alongside real (“target”) peptides, we search a matching set of “decoy” sequences (reversed/shuffled proteins that can’t actually be in the sample) to estimate how many of our matches are likely wrong — this is the standard target-decoy approach used across the proteomics field. Matches are ranked by score, and a q-value is computed for each one (see FDR and q-values, below). We keep matches that pass your chosen FDR threshold (default 1%), and attach a quantification (intensity) value to each one.

Key columns:

ColumnMeaning
scan_idWhich MS/MS spectrum this row came from
modified_sequencePeptide sequence with modifications shown, e.g. M(ox)PEFPLSPPK
clean_sequenceSame peptide with modifications stripped, e.g. PEFPLSPPK
chargeCharge state of the precursor ion
retention_timeWhen the peptide eluted from the LC column (minutes)
precursor_mzMeasured mass-to-charge of the precursor
scoreSearch engine confidence (roughly -15 to 15; higher = more confident)
qvalPSM-level q-value (FDR estimate) — see below
is_decoyTrue if this is a decoy match, used only for FDR calculation and not real biology
intensity (label-free/DIA) or intensity_1…N (TMT)Signal intensity for this PSM — see Intensity columns
protein_idsThe protein group this peptide was ultimately assigned to (after resolving shared peptides)
possible_protein_idsEvery protein this peptide sequence could theoretically belong to, before that resolution

When to use this table: when you care about individual spectra — e.g. inspecting a specific identification, computing your own custom peptide- or protein-level rollup, or investigating retention time/charge state behavior. Note it has one row per scan, so the same peptide can appear multiple times per file; don’t treat row count as “peptide count.”

What it is: one row per distinct peptide sequence (including its modification state) per file — the PSM table collapsed down to unique peptides.

How it’s generated: for each file, Tesorai groups all PSMs by spectrum first, keeps the single best-scoring match per spectrum, then groups those by peptide sequence (modified_sequence) and keeps only the best-scoring PSM representing each peptide. (For DIA or wide-window/chimeric DDA data, where one spectrum can genuinely contain several co-fragmented peptides, the spectrum-level step is skipped and peptides are collapsed directly.) The result: each peptide is represented once per file, by its most confident identification.

Importantly, q-values are recalculated from scratch at this level — target-decoy competition is re-run on the collapsed peptide list, not simply copied over from the PSM table. A peptide’s qval in this table can therefore differ from the qval of its best PSM in the PSM table.

Key columns: the same identification columns as the PSM table (modified_sequence, clean_sequence, score, qval, possible_protein_ids, retention time/m/z/charge of the representative PSM), minus the spectrum-specific and quantification columns. This table does not carry intensity values — if you need peptide-level quantification, use quantified_psm_fdr (which still has one row per peptide-per-scan, so you’ll aggregate intensity across scans yourself) or the protein-level intensities.

When to use this table: to answer “how many distinct peptides did we identify, and how confidently?” — e.g. peptide counts per sample, sequence coverage of a protein, or PTM site inventories. Not for quantification.

3. Protein table — quantified_protein_fdr

Section titled “3. Protein table — quantified_protein_fdr”

What it is: one row per protein group per file — the peptide identifications rolled up to the protein(s) they came from, with a summed/aggregated abundance estimate.

Protein inference: how peptides become proteins

Section titled “Protein inference: how peptides become proteins”

A peptide sequence is often shared by more than one protein (isoforms, paralogs, near-duplicate database entries). Tesorai resolves this with a razor/parsimony strategy, similar to the approach used by tools like MaxQuant and EPIFANY:

  1. Every identified peptide is matched (in silico digested) back against the FASTA database to find every protein it could have come from — a peptide’s full candidate list is preserved in possible_protein_ids.
  2. For peptides that map to more than one protein, Tesorai builds a graph connecting shared peptides to their candidate proteins, and — within each connected cluster — greedily picks the smallest set of proteins that explains the peptide evidence: it favors proteins with the most peptides uniquely their own, then proteins covering the most remaining shared peptides (“razor” peptides go to the protein group best supported by the rest of the evidence).
  3. Proteins that end up with exactly the same peptide evidence (indistinguishable by MS) are merged into one protein group, shown as a semicolon-separated list in protein_group_id (e.g. sp|P16949-2|STMN1_HUMAN;sp|P16949|STMN1_HUMAN).
  4. Each peptide is then assigned to its resolved group in protein_ids (in the PSM table) / rolled into identified_clean_sequences (in this table).

In short: protein_group_id represents “the smallest set of proteins that fully explains the peptides we saw,” not “every protein a peptide could theoretically belong to” (that broader list is possible_protein_ids/n_possible_proteins upstream).

As with peptides, protein-level q-values are computed independently via target-decoy competition on the rolled-up protein groups — a protein group is only called a “decoy” if all of its supporting peptides are decoys.

Key columns:

ColumnMeaning
protein_group_idSemicolon-joined list of indistinguishable proteins in this group
identified_clean_sequencesThe peptide sequences that support this group
spectral_countTotal number of PSMs supporting this group (a rough abundance proxy)
max_psm_scoreBest individual PSM score among the group’s peptides
protein_scoreOverall confidence score for the group
qvalProtein-level q-value (FDR estimate)
intensity_*Several different abundance estimates — see Intensity columns

When to use this table: this is the table to reach for when the question is “how much of protein X was in each sample” — differential abundance, volcano plots, pathway-level summaries, etc.

Across all three tables, FDR control uses the same underlying idea, applied independently to each level’s own population of matches:

  • Alongside every real (“target”) protein/peptide, Tesorai searches an equal-sized set of decoy sequences that cannot be biologically real (typically reversed proteins). Because decoys are fake, any decoy that scores well tells us something about how often real-looking but wrong matches occur by chance.
  • Matches are ranked by score, and at every rank we estimate what fraction of everything at-or-above that rank is likely a decoy (i.e., wrong). That running estimate is the q-value: “if I draw the cutoff here, what fraction of what I keep is expected to be false?”
  • A qval of 0.01 means: of everything at or above this confidence level, about 1% is expected to be a false identification.
  • This is computed separately at each level (PSM, peptide, protein) — a peptide’s q-value is not just inherited from its best PSM, and a protein’s q-value is not just inherited from its peptides. Each level re-runs target-decoy competition on its own rolled-up set of targets/decoys, because collapsing PSMs into peptides (or peptides into proteins) changes the underlying population and thus the error rate.
  • Your chosen FDR threshold (default 1%) is applied as a filter at each of these levels independently when building the final tables.

“Intensity” means different things depending on which table and column you’re looking at — this is the most common source of confusion, so here’s the full picture.

One intensity value per PSM (i.e., per peptide-in-a-specific-scan), computed by the quantification method appropriate to your acquisition type:

  • Label-free DDA: an OpenMS feature-finding algorithm integrates the MS1 peak area under the peptide’s isotope envelope.
  • TMT: reporter ion intensities are extracted per channel, giving one intensity_1intensity_N column per TMT channel (e.g. 10 columns for a TMT10-plex) instead of a single intensity column.
  • DIA: a precursor quantity is computed by integrating its MS2 peak areas.

At the protein level (quantified_protein_fdr)

Section titled “At the protein level (quantified_protein_fdr)”

Peptide-level intensities are combined into several different protein-level summaries, each with different strengths — pick the one that matches your analysis:

ColumnHow it’s computedBest for
intensity_uncertainty_awareA probabilistic model that weighs each peptide’s contribution by how reliable its identification is, rescaled to be on the same numeric scale as iBAQRecommended default. Generally the most accurate/lowest-noise estimate for comparing abundance across samples. Label-free only.
intensity_IBAQSum of peptide intensities, divided by the protein’s length (amino acid count)Rough estimate of absolute abundance, useful for comparing different proteins’ abundance within a sample. Falls back to this when the uncertainty-aware value isn’t available.
intensity_top3Average of the three most intense peptides for that proteinA classic, simple abundance proxy less sensitive to a protein’s total peptide count than a straight sum
intensity_lfqDirectLFQ algorithm — normalizes intensities across samples/files, correcting for shared-peptide ambiguity by routing each shared peptide to a single “lead” protein groupCross-sample normalization, comparable to MaxLFQ. Needs ≥2 files and ≥10 proteins in the job to be computed; label-free only.
intensitiesThe raw list of individual peptide intensities that fed the summaries aboveDiagnostics/inspection, not typically used directly for analysis

For TMT experiments, intensity_uncertainty_aware and intensity_lfq are not available (both require label-free MS1 quantification); instead you get per-channel versions of iBAQ and top-3 (intensity_1_IBAQintensity_N_IBAQ, intensity_1_top3intensity_N_top3).

There is no intensity column in pep_fdr. If you need peptide-level quantification, use quantified_psm_fdr and aggregate the PSM intensities for a given modified_sequence yourself, or work from the protein-level intensities list.


For questions about a specific job’s results, ask in the chat interface — it has direct access to these tables and can run custom analyses over them. If you have any other questions, please reach out to info@tesorai.com.