Update IDs and labels

Take a table of your own and add a column with each value’s current ID or label.

import pandas as pd
from pysec2pri import generate_ids, update_ids

df = pd.read_csv("genes.tsv", sep="\t")
out = update_ids(df, generate_ids("hgnc"), at="gene_id")

gene_id_primary is the new column. update_labels() is the same for symbols, and writes _current.

pysec2pri update-ids genes.tsv hgnc --at gene_id -o out.tsv
pysec2pri update-labels genes.tsv hgnc --at symbol -o out.tsv

Every row keeps its original value, and the new column shows the solved value:

the value is

the new column holds

retired

what it retired into

current

itself

not from this source

itself

both retired and current

nothing: an empty cell

Ambiguity

Ambiguity: HGNC:2 can be a retired ID that became HGNC:3, and the current ID of a different gene. One row says HGNC:2 and both readings are correct.

pysec2pri does not guess. The cell is left empty, and an empty cell is how you find the rows worth looking at:

out[out["gene_id_primary"] == ""]

To resolve them, you can give a hint: another column of the same row that says which entry it means.

Hints from a crosswalk

synonyms names a column of names for the row. xref names a column of identifiers from another vocabulary, such as an Ensembl gene ID next to the HGNC to be solved.

An xref hint needs a table saying which entry each of those identifiers belongs to. Bring your own with load_xref_mapping(). Any SSSOM file works, and so does a plain TSV of subject_id and object_id:

subject_id       object_id
ENSG00000121410  HGNC:5
ENSG00000175899  HGNC:7
from mapkgsutils.context import load_xref_mapping

out = update_ids(
    df,
    generate_ids("hgnc"),
    at="gene_id",
    xref="ensembl",
    xref_mapping=load_xref_mapping("ensembl_to_hgnc.tsv"),
)

Now an ambiguous gene_id is decided by that row’s ensembl value: the crosswalk says which gene it is, and that gene’s ID is the answer. Hints are only consulted for ambiguous rows, so a wrong one cannot spoil a row that was already clear.

Using a hint also adds a gene_id_primary_id column, holding the ID the row resolved to.

The same from the command line, with --xref-file for your own table:

pysec2pri update-ids genes.tsv hgnc --at gene_id \
    --xref ensembl --xref-file ensembl_to_hgnc.tsv

--xref-source downloads a crosswalk the source’s config already lists, instead of you supplying one. --xref-on says which vocabulary your column holds:

pysec2pri update-ids genes.tsv hgnc --at gene_id \
    --xref ensembl --xref-source hgnc_custom --xref-on ensembl

Report decisions

report_path (--report) writes down every hint it considered, whether it was accepted, and why:

stage         token   predicate_id  candidate  accepted  reason
xref_filter   ENSG_B                HGNC:3     True      no predicate given, assumed equivalence

It is a TSV, so read it back with pandas:

out = update_ids(
    df,
    generate_ids("hgnc"),
    at="gene_id",
    xref="ensembl",
    xref_mapping=load_xref_mapping("ensembl_to_hgnc.tsv"),
    report_path="decisions.tsv",
)

report = pd.read_csv("decisions.tsv", sep="\t")
report[~report["accepted"]]  # the hints that did not settle a row

One row per hint considered, not one per row of your data: a row with no ambiguity never consults a hint and never appears here.

Any equivalence predicate is accepted by default, including records with none. xref_predicates (--xref-predicate) narrows that to the ones you name.

Reference

Resolve secondary identifiers and previous labels to their primary form.

Applies mod:mapkgsutils.resolve.

Takes a single string delimited by |, ,, ;, or whitespace:

from pysec2pri import generate_ids, update_ids

ms = generate_ids("hgnc")
update_ids("HGNC:1234|HGNC:5678", ms)

DataFrame, annotating one or more columns:

update_ids(df, ms, at="gene_id")
update_ids(df, ms, at=["gene_id", "alt_id"])