Epidemiological linkage inference from temporal and genetic data.
Project description
EpiLink
EpiLink scores how compatible a pair of samples is with recent transmission scenarios using sampling-time differences and consensus genetic distance.
It is useful when you have:
- a sampling-time difference in days
- a consensus genetic distance in mutations
- a question like "is this pair more compatible with direct transmission or a recent shared ancestor?"
EpiLink returns typed score results with per-scenario compatibility summaries and can also sum scores across a user-defined target subset such as ["ad(0)", "ca(0,0)"].
Installation
From PyPI:
pip install epilink
Clone the repository first if you are starting from GitHub:
git clone https://github.com/ydnkka/epilink.git
cd epilink
The repository environment is the easiest way to get everything needed for the package, examples, and simulation helpers:
conda env create -f environment.yml
conda activate epilink
If you prefer pip:
python -m pip install -e .
python -m pip install networkx pandas
EpiLink requires Python 3.10 or newer.
Scenario labels
ad(0): direct ancestor-descendant transmissionad(1): ancestor-descendant transmission with one hidden intermediateca(0,0): a recent shared common ancestor with one branch to each sampled caseca(m_i,m_j): a common-ancestor scenario withm_iandm_jhidden generations on each branch
maximum_depth controls how many of these latent scenarios are generated.
Which method to use
score_pair(...): one observed pair, plus a full per-scenario breakdownscore_target(...): only the target score, for scalar or array inputspairwise_model(...): a cached scorer for repeatedly evaluating the same target subset
Each individual scenario compatibility lies in [0, 1]. If target contains multiple scenarios, target_compatibility is the sum across that subset, so it can be greater than 1.
API guarantees
score_pair(...)returns aPairCompatibilityResultobject with attribute access such asresult.target_labelsandresult.scenario_scores["ad(0)"].compatibility.simulate_genomic_sequences(...)returns aSimulationResultobject withpackedand optionalrawsequence sets, each exposingdeterministicandstochasticmembers.score_target(...)returns a scalarfloatfor scalar inputs and a NumPy array for broadcastable array inputs.- Result objects retain lightweight dictionary-style access for common keys to ease migration from earlier releases.
Reproducibility
- Randomness is controlled by the transmission profile RNG, or by the explicit
rng=argument passed toEpiLink. - For reproducible scores and simulations, construct profiles with a fixed
rng_seedand reuse the resulting model instance. score_pair(...)andpairwise_model(...)use cached Monte Carlo draws, so repeated evaluations on the same model are stable unless you replacedraws_by_scenario.
Performance and caching
EpiLink(...)precomputes scenario draws up front, so model construction is the main fixed cost.- Reuse one model instance for repeated scoring instead of rebuilding it inside loops.
- Use
pairwise_model(...)when scoring many observations against the same target subset. - For benchmarking and a fuller discussion, see docs/performance.md and run
python -m docs.benchmark_api.
Quick start
from epilink import EpiLink, InfectiousnessToTransmission
profile = InfectiousnessToTransmission(rng_seed=2026)
model = EpiLink(
transmission_profile=profile,
maximum_depth=2,
mc_samples=20000,
target=["ad(0)", "ca(0,0)"],
mutation_process="stochastic",
)
result = model.score_pair(
sample_time_difference=3.0,
genetic_distance=2.0,
)
print(result.target_labels)
print(result.target_compatibility)
print(result.scenario_scores["ad(0)"].compatibility)
More examples
Score only a target subset
Use score_target when you only care about the combined score:
score = model.score_target(
sample_time_difference=3.0,
genetic_distance=2.0,
target=["ad(0)", "ad(1)", "ca(0,0)"],
)
print(score)
Use Scenario objects instead of strings
from epilink import Scenario
score = model.score_target(
sample_time_difference=3.0,
genetic_distance=2.0,
target=[
Scenario.ancestor_descendant(0),
Scenario.common_ancestor(0, 0),
],
)
Score many pairs at once
score_target and pairwise_model broadcast NumPy inputs, so you can score a whole grid or batch efficiently:
import numpy as np
pairwise = model.pairwise_model(target=["ad(0)", "ca(0,0)"])
time_differences = np.array([[0.0], [2.0], [4.0]])
genetic_distances = np.array([[0.0, 1.0, 2.0, 3.0]])
scores = pairwise(time_differences, genetic_distances)
print(scores.shape) # (3, 4)
Build a toy simulated pair table
The simulation helpers are useful for generating synthetic examples and benchmarking downstream workflows:
import networkx as nx
from epilink import (
build_pairwise_case_table,
simulate_epidemic_dates,
simulate_genomic_sequences,
)
tree = nx.DiGraph(
[
("case-0", "case-1"),
("case-0", "case-2"),
]
)
dated_tree = simulate_epidemic_dates(profile, tree, fraction_sampled=1.0)
simulated = simulate_genomic_sequences(profile, dated_tree, genome_length=500)
pair_table = build_pairwise_case_table(simulated.packed, dated_tree)
print(pair_table.head())
Mutation models
mutation_process="deterministic"compares the observation with expected mutation countsmutation_process="stochastic"compares the observation with Poisson mutation-count draws
The stochastic option is usually the better choice when you want mutation-count variability to be part of the score.
Background and usage guide
- Manuscript: docs/epilink.md
- Usage guide: docs/usage_guide.ipynb
- Latent histories: docs/epilink_scenarios.svg
- Workflow figure: docs/epilink_schematic.svg
- Performance guide: docs/performance.md
Citation
If you use EpiLink in research, please cite the software metadata in CITATION.cff. The underlying infectiousness model is:
- Hart WS, Maini PK, Thompson RN. High infectiousness immediately before COVID-19 symptom onset highlights the importance of continued contact tracing. eLife. 2021;10:e65534. http://dx.doi.org/10.7554/eLife.65534
License
MIT. See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file epilink-0.1.4.tar.gz.
File metadata
- Download URL: epilink-0.1.4.tar.gz
- Upload date:
- Size: 1.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dfcd98f96c6df25ea468672d06158a908e37995898d04ebfb86ff257b1fdef03
|
|
| MD5 |
d05e43bea492dacd037ebb75fef0d408
|
|
| BLAKE2b-256 |
0fb8ae081310033cc9a7c6eceb38de6ab3195fa6af2de701f2b414387885bb40
|
Provenance
The following attestation bundles were made for epilink-0.1.4.tar.gz:
Publisher:
release.yml on ydnkka/epilink
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epilink-0.1.4.tar.gz -
Subject digest:
dfcd98f96c6df25ea468672d06158a908e37995898d04ebfb86ff257b1fdef03 - Sigstore transparency entry: 1159118616
- Sigstore integration time:
-
Permalink:
ydnkka/epilink@c37d45bc357e43648e6904ad1ce1f3a17aa7b5b8 -
Branch / Tag:
refs/tags/v0.1.4-alpha - Owner: https://github.com/ydnkka
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c37d45bc357e43648e6904ad1ce1f3a17aa7b5b8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file epilink-0.1.4-py3-none-any.whl.
File metadata
- Download URL: epilink-0.1.4-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
106f613702acf0a41ff6260a628939d2b3b830a5cb408bacebc462f4d5797ec6
|
|
| MD5 |
8cd95c91ae1fbe0d5bbdb51bb0fb0b00
|
|
| BLAKE2b-256 |
7a3b555b41002894885b40e24e4e255740b0ec806c116ed4817167833a5a3efe
|
Provenance
The following attestation bundles were made for epilink-0.1.4-py3-none-any.whl:
Publisher:
release.yml on ydnkka/epilink
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
epilink-0.1.4-py3-none-any.whl -
Subject digest:
106f613702acf0a41ff6260a628939d2b3b830a5cb408bacebc462f4d5797ec6 - Sigstore transparency entry: 1159118692
- Sigstore integration time:
-
Permalink:
ydnkka/epilink@c37d45bc357e43648e6904ad1ce1f3a17aa7b5b8 -
Branch / Tag:
refs/tags/v0.1.4-alpha - Owner: https://github.com/ydnkka
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@c37d45bc357e43648e6904ad1ce1f3a17aa7b5b8 -
Trigger Event:
release
-
Statement type: