Extract HIrisPlex-S prediction markers

Result: data/processed/hirisplexs2018_markers.csv (36 gene→rsID markers, 16 genes) derived from a committed, transcribed raw marker table. Fully offline and deterministic.

Why a transcribed raw table. The markers were originally parsed from the Chaitanya et al. 2018 paper (Elsevier subscription), which is not redistributed in this repo. The gene→rsID pairs are factual data (SNP identifiers), not copyrightable article text, so they are transcribed into a committed raw CSV with the page citation and treated as this notebook’s raw input. Source article: DOI 10.1016/j.fsigen.2018.04.004 (see data/raw/papers/REFERENCES.md).

Raw input (committed): data/raw/hirisplexs2018/hirisplexs2018_markers_raw_transcribed.csv — 36 rows, each gene, rsid, novel_17plex_skin_panel, with source_citation (Table 1, pp.3-5).

Documented transcription corrections (from docs/specs/hirisplexs2018.spec.md): one OCR fix rs228479 → rs2228479 (MC1R R163Q); one OCR duplicate rs18004141 dropped. The transcribed table already carries the corrected values.

Key terms — so this notebook stands on its own (you shouldn’t need the other notebooks to read this one).

  • HIrisPlex-S — a published, forensically validated DNA test that predicts a person’s eye, hair, and skin color from a fixed panel of pigmentation SNPs (Chaitanya et al. 2018). Here it serves only as an external, independently-validated reference list of “known” pigmentation-predictive variants; this notebook just transcribes and emits its marker table — it runs no prediction. (“HIrisPlex” is the earlier eye+hair version; the “-S” release added skin.)
  • 17-plex skin panel (novel_17plex_skin_panel column) — the 17-SNP subset the paper introduced specifically for skin-color prediction; the column flags which of the 36 markers belong to that skin panel versus the older eye/hair markers.
Show code
import pandas as pd
RAW = "data/raw/hirisplexs2018/hirisplexs2018_markers_raw_transcribed.csv"
raw = pd.read_csv(RAW)
print("transcribed markers:", raw.shape)
print("citation:", raw["source_citation"].iloc[0])

Step 1 — Assert the canonical panel counts (36 markers / 16 genes / 17 skin-panel SNPs)

Show code
n_markers = len(raw)
n_genes   = raw["gene"].nunique()
n_skin    = int(raw["novel_17plex_skin_panel"].sum())
print(f"markers: {n_markers}  |  genes: {n_genes}  |  novel-17plex-skin SNPs: {n_skin}")
assert n_markers == 36, f"expected 36 markers, got {n_markers}"
assert n_genes   == 16, f"expected 16 genes, got {n_genes}"
assert n_skin    == 17, f"expected 17 skin-panel SNPs, got {n_skin}"
# payoff-locus coverage (complete for the two video loci):
mc1r_red = {"rs1805007","rs1805008","rs1805006","rs11547464","rs885479","rs2228479","rs1110400","rs3212355"}
have = set(raw.loc[raw["gene"]=="MC1R","rsid"])
print("MC1R red-hair set complete:", mc1r_red <= have)
blue = {("HERC2","rs12913832"),("OCA2","rs1800407")}
pairs = set(map(tuple, raw[["gene","rsid"]].values))
print("blue-eye markers present:", blue <= pairs)

Step 2 — Emit the processed marker table (restore the published column name)

Show code
out = raw[["gene","rsid","novel_17plex_skin_panel"]].rename(
    columns={"novel_17plex_skin_panel":"in_novel_17plex_skin"})
out.to_csv("data/processed/hirisplexs2018_markers.csv", index=False)
print("wrote", len(out), "markers ->", "data/processed/hirisplexs2018_markers.csv")
out.head()
Back to top