Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Convert between gene identifier systems including Ensembl, Entrez, HGNC symbols, and UniProt. Use when mapping IDs for pathway analysis or matching different data sources.
.claude/skills/bio-expression-matrix-gene-id-mapping/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 84% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 118% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 42% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 60% | 0% |
| case-11 | ✓→✓ | = Same ✓ | 57% | 0% |
<!--
#
#
-->
pythonimport mygene import pandas as pd mg = mygene.MyGeneInfo() # Ensembl to Symbol ensembl_ids = ['ENSG00000141510', 'ENSG00000012048', 'ENSG00000141736'] results = mg.querymany(ensembl_ids, scopes='ensembl.gene', fields='symbol', species='human') mapping = {r['query']: r.get('symbol', None) for r in results} # {'ENSG00000141510': 'TP53', 'ENSG00000012048': 'BRCA1', 'ENSG00000141736': 'ERBB2'} # Symbol to Entrez symbols = ['TP53', 'BRCA1', 'ERBB2'] results = mg.querymany(symbols, scopes='symbol', fields='entrezgene', species='human') mapping = {r['query']: r.get('entrezgene', None) for r in results} # Ensembl to multiple fields results = mg.querymany(ensembl_ids, scopes='ensembl.gene', fields=['symbol', 'entrezgene', 'uniprot'], species='human')
pythonfrom pyensembl import EnsemblRelease # Load Ensembl release (downloads automatically first time) ensembl = EnsemblRelease(110, species='human') # or 'mouse' # Gene ID to symbol gene = ensembl.gene_by_id('ENSG00000141510') print(gene.gene_name) # TP53 # Symbol to gene ID gene = ensembl.genes_by_name('TP53')[0] print(gene.gene_id) # ENSG00000141510 # Batch conversion def ensembl_to_symbol(ensembl_ids, release=110): ens = EnsemblRelease(release, species='human') mapping = {} for eid in ensembl_ids: try: gene = ens.gene_by_id(eid.split('.')[0]) # Remove version mapping[eid] = gene.gene_name except ValueError: mapping[eid] = None return mapping
pythonimport gseapy as gp # Ensembl to Symbol using Enrichr gene_list = ['ENSG00000141510', 'ENSG00000012048'] converted = gp.biomart.ensembl2name(gene_list, organism='hsapiens')
rlibrary(biomaRt) # Connect to Ensembl ensembl <- useEnsembl(biomart='genes', dataset='hsapiens_gene_ensembl') # Ensembl to Symbol ensembl_ids <- c('ENSG00000141510', 'ENSG00000012048', 'ENSG00000141736') results <- getBM( attributes=c('ensembl_gene_id', 'hgnc_symbol', 'entrezgene_id'), filters='ensembl_gene_id', values=ensembl_ids, mart=ensembl ) # Symbol to Ensembl symbols <- c('TP53', 'BRCA1', 'ERBB2') results <- getBM( attributes=c('hgnc_symbol', 'ensembl_gene_id'), filters='hgnc_symbol', values=symbols, mart=ensembl ) # All available attributes listAttributes(ensembl)
rlibrary(org.Hs.eg.db) # Human library(AnnotationDbi) # Ensembl to Symbol ensembl_ids <- c('ENSG00000141510', 'ENSG00000012048') symbols <- mapIds(org.Hs.eg.db, keys=ensembl_ids, keytype='ENSEMBL', column='SYMBOL') # Symbol to Entrez symbols <- c('TP53', 'BRCA1') entrez <- mapIds(org.Hs.eg.db, keys=symbols, keytype='SYMBOL', column='ENTREZID') # Available keytypes keytypes(org.Hs.eg.db) # ENSEMBL, ENSEMBLPROT, ENSEMBLTRANS, ENTREZID, SYMBOL, UNIPROT, etc.
pythonimport pandas as pd import mygene def map_count_matrix_ids(counts, from_type='ensembl.gene', to_type='symbol', species='human'): '''Map gene IDs in count matrix index.''' mg = mygene.MyGeneInfo() # Remove version numbers from Ensembl IDs clean_ids = [g.split('.')[0] for g in counts.index] # Query mygene results = mg.querymany(clean_ids, scopes=from_type, fields=to_type, species=species) # Build mapping mapping = {} for r in results: if to_type in r: mapping[r['query']] = r[to_type] # Apply mapping new_index = [mapping.get(g.split('.')[0], g) for g in counts.index] counts_mapped = counts.copy() counts_mapped.index = new_index # Handle duplicates (sum) counts_mapped = counts_mapped.groupby(counts_mapped.index).sum() return counts_mapped # Usage counts_symbols = map_count_matrix_ids(counts, 'ensembl.gene', 'symbol')
rlibrary(biomaRt) map_count_matrix_ids <- function(counts, from_type='ensembl_gene_id', to_type='hgnc_symbol') { ensembl <- useEnsembl(biomart='genes', dataset='hsapiens_gene_ensembl') # Remove version numbers clean_ids <- gsub('\\..*', '', rownames(counts)) # Get mapping mapping <- getBM( attributes=c(from_type, to_type), filters=from_type, values=clean_ids, mart=ensembl ) # Merge and aggregate duplicates counts$gene_id <- clean_ids merged <- merge(counts, mapping, by.x='gene_id', by.y=from_type, all.x=TRUE) merged$gene_id <- NULL # Use symbol as rowname, sum duplicates rownames(merged) <- merged[[to_type]] merged[[to_type]] <- NULL counts_mapped <- aggregate(. ~ rownames(merged), data=merged, FUN=sum) rownames(counts_mapped) <- counts_mapped[,1] counts_mapped <- counts_mapped[,-1] return(counts_mapped) }
pythondef robust_id_mapping(gene_ids, from_type, to_type, species='human'): '''Map IDs with fallback for unmapped genes.''' import mygene mg = mygene.MyGeneInfo() clean_ids = [g.split('.')[0] for g in gene_ids] results = mg.querymany(clean_ids, scopes=from_type, fields=to_type, species=species) mapping = {} unmapped = [] for r in results: original = gene_ids[clean_ids.index(r['query'])] if to_type in r: mapping[original] = r[to_type] else: mapping[original] = original # Keep original if unmapped unmapped.append(original) print(f'Mapped: {len(gene_ids) - len(unmapped)}/{len(gene_ids)}') print(f'Unmapped: {len(unmapped)}') return mapping, unmapped
| Type | Example | Use Case | |------|---------|----------| | Ensembl Gene | ENSG00000141510 | RNA-seq, GTF files | | Ensembl Transcript | ENST00000269305 | Transcript-level analysis | | Entrez Gene | 7157 | NCBI databases, KEGG | | HGNC Symbol | TP53 | Human readable | | UniProt | P04637 | Protein databases | | RefSeq | NM_000546 | NCBI RefSeq |
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 12,684 | 10,776 | -15% | 1 | 1 | 0% | 2,634 | 4,840 | +84% | 0 | 0 | — |
case-11 | pass→pass | 15,013 | 12,045 | -20% | 1 | 1 | 0% | 2,942 | 4,613 | +57% | 0 | 0 | — |
case-02 | pass→pass | 6,268 | 4,033 | -36% | 1 | 1 | 0% | 1,334 | 3,140 | +135% | 0 | 0 | — |
case-03 | pass→pass | 6,989 | 3,188 | -54% | 1 | 1 | 0% | 1,244 | 2,902 | +133% | 0 | 0 | — |
case-04 | pass→pass | 11,317 | 6,219 | -45% | 1 | 1 | 0% | 2,298 | 3,441 | +50% | 0 | 0 | — |
case-05 | pass→pass | 12,710 | 7,960 | -37% | 1 | 1 | 0% | 2,471 | 3,752 | +52% | 0 | 0 | — |
case-06 | fail→pass | 6,600 | 3,048 | -54% | 1 | 1 | 0% | 1,330 | 2,906 | +118% | 0 | 0 | — |
case-07 | pass→pass | 7,577 | 3,381 | -55% | 1 | 1 | 0% | 1,598 | 3,021 | +89% | 0 | 0 | — |
case-08 | pass→pass | 8,410 | 6,378 | -24% | 1 | 1 | 0% | 1,711 | 3,590 | +110% | 0 | 0 | — |
case-09 | pass→pass | 5,487 | 3,067 | -44% | 1 | 1 | 0% | 1,126 | 2,871 | +155% | 0 | 0 | — |
case-10 | pass→pass | 9,394 | 4,992 | -47% | 1 | 1 | 0% | 1,857 | 3,307 | +78% | 0 | 0 | — |
case-12 | fail→pass | 13,448 | 8,769 | -35% | 1 | 1 | 0% | 2,554 | 3,627 | +42% | 0 | 0 | — |
case-13 | fail→pass | 13,987 | 8,529 | -39% | 1 | 1 | 0% | 2,393 | 3,830 | +60% | 0 | 0 | — |
case-14 | pass→pass | 15,706 | 6,745 | -57% | 1 | 1 | 0% | 2,028 | 3,712 | +83% | 0 | 0 | — |
case-15 | pass→pass | 7,786 | 4,839 | -38% | 1 | 1 | 0% | 1,464 | 3,233 | +121% | 0 | 0 | — |
case-16 | pass→pass | 7,347 | 4,248 | -42% | 1 | 1 | 0% | 1,279 | 3,105 | +143% | 0 | 0 | — |
case-17 | pass→pass | 5,956 | 6,181 | +4% | 1 | 1 | 0% | 1,170 | 3,203 | +174% | 0 | 0 | — |
case-18 | pass→pass | 2,759 | 3,011 | +9% | 1 | 1 | 0% | 477 | 2,875 | +503% | 0 | 0 | — |
case-19 | pass→pass | 6,142 | 2,648 | -57% | 1 | 1 | 0% | 1,084 | 2,687 | +148% | 0 | 0 | — |
case-20 | pass→pass | 5,434 | 3,715 | -32% | 1 | 1 | 0% | 993 | 3,000 | +202% | 0 | 0 | — |
case-21 | pass→pass | 9,695 | 5,114 | -47% | 1 | 1 | 0% | 1,333 | 3,204 | +140% | 0 | 0 | — |
case-22 | pass→pass | 14,436 | 12,393 | -14% | 1 | 1 | 0% | 2,700 | 4,451 | +65% | 0 | 0 | — |
case-23 | pass→pass | 11,345 | 7,450 | -34% | 1 | 1 | 0% | 2,373 | 3,734 | +57% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +17 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +23% |
Other measured skills in the registry, with their headline benchmark lift.