HeteroSplit
Leakage-safe entity-disjoint splits and audits for heterogeneous link-prediction datasets.
HeteroSplit constructs, validates, and reports cold-start / inductive splits for heterogeneous link-prediction tasks (drug–drug–cell-line synergy, drug–target interaction, recommendation, knowledge graphs). It is designed to complement PyTorch Geometric — it focuses narrowly on split semantics and leakage auditing, and does not replace PyG's loaders, samplers, or training stack.
Status: early release (
0.1.x). APIs may change. This is positioned as a reusable implementation of entity-disjoint split policies and leakage audits for PyGHeteroDatalink-prediction tasks — not (yet) a research novelty claim.
Why
Graph libraries make random node/edge splitting easy, but cold-start experiments often rely on one-off scripts with ambiguous semantics. A nominally "cold" test set can still leak information through:
- the same entity appearing in training under another edge or relation;
- reverse edges left in the message-passing graph;
- an unordered pair reversed across splits;
- context entities (e.g. cell lines) crossing a supposedly disjoint boundary;
- features / precomputed embeddings fit using held-out entities;
- negative sampling that pulls entities or pairs from the wrong regime.
HeteroSplit makes the split contract explicit, enforces it, and produces evidence (a serializable manifest + audit report) that the contract holds.
Why it matters (real DrugComb): a small GraphSAGE link predictor scores AUC 0.84 under a random split but 0.27 on genuinely unseen drugs (either-cold-start) — random splitting massively overestimates cold-start performance. See benchmarks.
Install
The correctness core is pure Python + NumPy:
pip install heterosplit
PyTorch Geometric integration is an optional extra:
pip install "heterosplit[pyg]"
From source (development)
This project uses uv:
git clone https://github.com/ZubairQazi/heterosplit
cd heterosplit
uv sync # creates .venv and installs the dev toolchain
uv run pytest # run the test suite
uv run --extra pyg pytest # include the PyG adapter tests
Quickstart
from heterosplit import make_synthetic_dataset, split_records
# A DrugComb-shaped dataset: (drug, drug, cell-line) synergy observations.
# Swap in your own PredictionRecords / HeteroData for real data.
data = make_synthetic_dataset(
n_records=5000,
n_source_entities=120,
n_context_entities=30,
n_labels=2,
source_type="drug",
context_type="cell_line",
relation="synergy",
seed=42,
)
# Joint cold-start: a test triple must involve an unseen drug AND an unseen cell line.
spec = data.spec(
"joint_cold_start",
holdout={"drug": "either", "cell_line": "all"},
ratios=(0.8, 0.1, 0.1),
stratify_by="label",
seed=42,
)
result = split_records(data.records, spec)
result.audit.raise_for_leakage() # fails loudly on any leakage
result.manifest.save("split-manifest.json") # deterministic, reloadable
train_edges = result.message_passing_edge_index() # leakage-safe training graph
Runnable versions live in examples/ (quickstart.py,
recommendation.py, drugcomb.py, corrupted_leakage.py), or try the CLI:
uv run heterosplit demo --regime joint_cold_start
uv run heterosplit split --input data.csv --spec spec.json --out-dir out/
Real data: DrugComb
The DrugComb drug–drug–cell-line synergy corpus is wired up directly (CC-BY-4.0):
from heterosplit.datasets.drugcomb import download_drugcomb_summary, load_drugcomb_csv
download_drugcomb_summary("drugcomb.csv") # ~1.4 GB, once
records = load_drugcomb_csv("drugcomb.csv", max_rows=200_000) # streams; filters mono-therapy rows
records_from_drugcomb(frame, ...) maps an in-memory DrugComb frame (dict or DataFrame)
if you already have one.
Documentation
Split taxonomy (v1 target)
| Regime | Test-set contract |
|---|---|
| Random / transductive | Test edges are unseen; entities may have appeared in training. |
| Pair cold-start | The (s, d) pair is unseen, but each entity may appear separately. |
| Source cold-start | Test source entities never appear as training sources. |
| Destination cold-start | Test destination entities never appear as training destinations. |
| Either-entity cold-start | At least one endpoint of each test edge is unseen. |
| Both-entity cold-start | Both endpoints of every test edge are unseen. |
| Context cold-start | Test context entities never occur in training. |
| Joint cold-start | A configured combination of endpoint and context disjointness. |
Leakage audit & manifests
Every split ships with an audit and a reproducible manifest:
result.auditturns the regime's contract into machine-checkable findings — entity / pair / context overlap (across all splits, including val-vs-test), reversed unordered pairs, message-passing leakage, duplicate observations, and optional negative-sample / feature-provenance checks. Each finding has a count, severity, and concrete offending ids;raise_for_leakage()fails on any violation.result.manifestrecords library/schema versions, a collision-resistant input fingerprint, the normalized spec, per-split counts, and hashes of the split indices.manifest.digest()is a stable reproducibility key; runtime/memory measurements are kept separate so a fixed input + spec + seed always produce the same digest.
License
Metadata
Release files for heterosplit 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| heterosplit-0.1.0.tar.gz | 268.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| heterosplit-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 331.8 kB
Release files / heterosplit-0.1.0.tar.gz
| Download URL | heterosplit-0.1.0.tar.gz |
|---|---|
| Size | 268.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bb8f39c951bf07322b496974fb010a7dc7f9bb64164251536f3d34d6e6d53655
|
|
BLAKE2b-256 checksum How to use checksums |
7f822003e055e8752da21e2f86993bec5ac7c96d5087d516a6db618ccb1bfda5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / heterosplit-0.1.0-py3-none-any.whl
| Download URL | heterosplit-0.1.0-py3-none-any.whl |
|---|---|
| Size | 63.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fbc41db611331229c044a02bb0b7dbaf58f7fa7c216bcd386ce80c9122af8b80
|
|
BLAKE2b-256 checksum How to use checksums |
e7ec0cd12a698afc0b119c9bcde6873719cdfc7210d378d95559a4e096c7deba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency log