.summarize_peptides_by_neighbourhood_union

proteopy.pp.summarize_peptides_by_neighbourhood_union(adata, annotator, *, protein_col='protein_id', peptide_col='peptide_id', top_n=1, keep_less=False, id_from='top_ranked', mod_regex='\\\\(UniMod:[0-9]+\\\\)', alphabet='ACDEFGHIKLMNPQRSTVWYBJOUXZ', on_unknown_protein='raise', on_unlocated_peptide='raise', tie_break_key=<function letters_first_key>, zero_to_na=False, fill_na=None, sort_descending_id=True, key_added='peptide_ids', keep_var_cols=None, inplace=True, verbose=False)[source]

Collapse peptides by their position in the protein sequence.

Reimplements CCprofiler’s summarizeAlternativePeptideSequences(topN = 1) [1]. Peptide positions are resolved from annotator, peptides are grouped by the union of their positional neighbourhoods, and the most abundant member of each group is selected while the rest are discarded.

Grouping happens within a protein. Each peptide x carries the closed 1-based interval [s(x), e(x)] where its modification-stripped sequence first occurs, and any comparison involving an unlocated peptide is false:

N(x) = { q : s(q) in [s(x), e(x)] or e(q) in [s(x), e(x)] }
L(x) = union of { N(y) : x in N(y) }
G(x) = { q : L(q) = L(x) }

N is asymmetric — a peptide lying strictly inside x is in N(x) but not the reverse — and L is a one-hop union rather than a transitive closure, so a chain of overlaps can yield several groups instead of one. Unlocated peptides share the empty label and so collapse into a single group per protein.

Members of a group are ordered by (T(x) is missing, -T(x), tie_break_key(id(x))), where T(x) is the intensity of x summed over samples. The leading top_n are kept and one row survives per group.

Missing values are deprioritised, not removed. T propagates them, so an incomplete peptide sorts last and loses to any complete competitor however small the competitor’s values; when every member is incomplete, tie_break_key alone decides and the winner passes through with its missing values intact. At top_n = 1 the surviving row is copied verbatim, so nothing is created or spread; at top_n > 1 the sum propagates, and an all-missing group sums to missing.

Parameters:
  • adata (AnnData) – Peptide-level data. Only .X is read and written.

  • annotator (str | Path | dict) – Path to a FASTA file, or a pre-parsed {accession: sequence} mapping, supplying the protein sequences that peptide positions are resolved against.

  • protein_col (str, optional) – Columns in .var holding the protein and peptide identifiers.

  • peptide_col (str, optional) – Columns in .var holding the protein and peptide identifiers.

  • top_n (int, optional) – How many of each group’s most abundant members contribute to the output value. 1 selects a single peptide and copies its intensities; above 1 the selected members are summed.

  • keep_less (bool, optional) – If False, discard groups with fewer than top_n members. Has no effect at top_n=1, since every group has a member.

  • id_from ({'top_ranked'}, optional) – How the surviving row is identified. Only 'top_ranked' is implemented: the row takes the identifier of the group’s most abundant member. This deviates from CCprofiler, which renames the row to a comma-joined list of the summed identifiers and thereby breaks its own annotation join.

  • mod_regex (str, optional) – Everything in an identifier that is not protein sequence. The pattern must cover every annotation present; whatever it fails to match is searched for verbatim, and the alphabet check turns an incomplete pattern into an error rather than a silently unlocatable peptide.

  • alphabet (iterable of str, optional) – Characters permitted in a stripped identifier. Defaults to the IUPAC one-letter codes, which include selenocysteine and the ambiguity codes.

  • on_unknown_protein ({'raise', 'skip', 'keep'}, optional) – What to do with a protein absent from annotator. 'skip' discards its peptides; 'keep' gives them NaN positions, so they share the empty label, collapse into one group, and the single survivor is removed downstream by a peptide-count filter. 'keep' is the CCprofiler behaviour.

  • on_unlocated_peptide ({'raise', 'skip', 'keep'}, optional) – What to do with a peptide whose sequence does not occur in its protein. 'keep' is the CCprofiler behaviour, which is silent about this case; 'raise' is the default because that silence is the reference’s real blind spot.

  • tie_break_key (callable, optional) – Key applied to the peptide identifier to resolve equal totals. Defaults to an ordering that places non-letters after letters, so ( and [ both sort after Z and an unmodified identifier wins a tie against any annotated form of itself.

  • zero_to_na (bool, optional) – If True, treat zeros as missing before ranking.

  • fill_na (float | int | None, optional) – Replace missing values with this constant before ranking. Mutually exclusive with zero_to_na. Note that 0 is not faithful: it gives an incomplete peptide a real total and can win it a ranking it should have lost.

  • sort_descending_id (bool, optional) – Order output variables by descending identifier, matching the reference’s closing setorder(traces, -id). Row order is load-bearing downstream, where average-linkage clustering breaks its own ties by row order.

  • key_added (str, optional) – .var column receiving the ';'-joined identifiers of all group members.

  • inplace (bool, optional) – If True, modify adata in place. Otherwise return a new AnnData.

  • verbose (bool, optional) – Print a peptide-count summary.

  • keep_var_cols (list[str] | None)

Returns:

The summarised object when inplace=False, otherwise None.

.var is reduced to peptide_id, protein_id, peptide_start, peptide_end, key_added, n_grouped and anything named in keep_var_cols. Other annotations are dropped: the surviving row’s metadata is one member’s, not the group’s, and carrying it would invite it to be read as representative. Layers are dropped for the same reason. .X is always dense, including when the input was sparse.

Return type:

AnnData or None

Raises:

ValueError – If an argument is invalid; if .var already holds a column this function writes; if a stripped identifier contains non-amino-acid characters; or, under the default policies, if a protein is absent from annotator or a peptide is not found in its protein sequence.

See also

summarize_overlapping_peptides

groups by substring containment and aggregates the members, rather than grouping by position and selecting among them.

Examples

Four peptides forming a chain in which only adjacent pairs overlap, plus CDE lying strictly inside ACDEF. Three groups form — {ACDEF, CDE}, {EFGHI, HIKLM} and {LMNPQ} — so three of the five peptides survive, each represented by its most abundant member.

>>> import numpy as np
>>> import pandas as pd
>>> from anndata import AnnData
>>> import proteopy as pr
>>> pids = ["ACDEF", "CDE", "EFGHI", "HIKLM", "LMNPQ"]
>>> adata = AnnData(
...     X=np.array([[30.0, 5.0, 20.0, 99.0, 40.0]]),
...     obs=pd.DataFrame({"sample_id": ["s1"]}, index=["s1"]),
...     var=pd.DataFrame(
...         {"peptide_id": pids, "protein_id": ["P1"] * 5},
...         index=pids,
...     ),
... )
>>> out = pr.pp.summarize_peptides_by_neighbourhood_union(
...     adata, {"P1": "ACDEFGHIKLMNPQRSTVWY"}, inplace=False,
... )
>>> out.var_names.tolist()
['LMNPQ', 'HIKLM', 'ACDEF']
>>> out.var["peptide_ids"].tolist()
['LMNPQ', 'EFGHI;HIKLM', 'ACDEF;CDE']
>>> out.X
array([[40., 99., 30.]])

References