Node2Vec embeddings for cross-study metabolomics co-response graphs

128-dimensional Node2Vec embeddings for two undirected graphs of metabolite co-response edges that pass a chi-square validity filter (every expected frequency β‰₯ 5). Held-out link prediction reaches AUC 0.932 and 0.928, against degree-only baselines of 0.826 and 0.888.

The graphs, node properties and full pipeline are in the companion dataset repository: kozo2/metabolomics-edges-expected-ge5.

Files

File Contents Size
edge_ML_filtered_expected_ge5_n2v.pt {embedding: [848, 128] float32, node_id: [848], args: {...}} 453 KB
edge_MLvsMW_filtered_expected_ge5_n2v.pt {embedding: [15758, 128] float32, node_id: [15758], args: {...}} 8.6 MB
node2vec_model.py, config.py Model definition, training loop, embedding export β€”
heldout_check.py The held-out link-prediction evaluation reported below β€”

Each file records the exact hyperparameters that produced it under args, and node_id[i] is the original study/assay/feature ID of embedding row i.

Using it

import torch

ck = torch.load("edge_MLvsMW_filtered_expected_ge5_n2v.pt", weights_only=False)
z = torch.nn.functional.normalize(ck["embedding"], dim=1)   # cosine space
idx = {node: i for i, node in enumerate(ck["node_id"])}

q = z[idx["MTBLS311_0001_00001537"]]
top = (z @ q).topk(11).indices[1:]                          # drop self
print([ck["node_id"][i] for i in top])

Scores are cosine similarities β€” that is the metric the embeddings were trained under random walks and evaluated with, so use normalized vectors rather than raw dot products.

Training

edge_ML edge_MLvsMW
graph 848 nodes, 3,697 edges 15,758 nodes, 89,277 edges
parameters 108,544 2,017,024
embedding_dim 128 128
walk_length / context_size 20 / 10 20 / 10
walks_per_node / negatives 10 / 1 10 / 1
p / q 1.0 / 1.0 (unbiased) 1.0 / 1.0 (unbiased)
batch_size / lr / optimizer 128 / 0.01 / SparseAdam 128 / 0.01 / SparseAdam
epochs / wall time 200 / 31 s 200 / 3 m 05 s
loss, first β†’ last 9.02 β†’ 0.815 6.73 β†’ 0.876

Trained on one NVIDIA H100 NVL. sparse=True makes the embedding table the only parameter tensor, which is why the optimizer is SparseAdam.

Evaluation

heldout_check.py deduplicates undirected edges, holds out a random 10%, retrains from scratch on the remaining 90%, then scores held-out edges against an equal number of sampled non-edges by cosine similarity. The control is the preferential-attachment baseline d_u Β· d_v on training degrees, which answers whether the embedding learned anything beyond "popular nodes connect".

edge_ML edge_MLvsMW
train / held-out edges 3,328 / 369 80,350 / 8,927
nodes isolated by the split 42 413
held-out AUC (never seen) 0.932 0.928
train AUC (in-sample) 0.985 0.985
degree baseline (held-out) 0.826 0.888
margin over baseline +0.106 +0.040

Species neighbour purity β€” of each node's 10 nearest embeddings by cosine, the fraction sharing its species label β€” is 48.8% overall for edge_ML and 59.2% for edge_MLvsMW, rising to 75–79% for the dominant host species. For the bipartite edge_MLvsMW graph, the same measure on source database gives 67.5% overall (75.4% ST, 47.7% MTBLS).

Caveats

  • Training budget matters more than it looks. At 20 epochs, edge_ML scored a held-out AUC of 0.791 β€” below its own 0.826 degree baseline. The embeddings only beat preferential attachment once training converges. --epochs defaults to 200 for this reason; do not shorten it without re-running heldout_check.py.
  • On edge_MLvsMW the margin over the degree baseline is thin (+0.040). That graph is bipartite with a few very high-degree studies, so much of its link structure is explained by degree alone.
  • edge_MLvsMW loss is flat from about epoch 19, so 200 epochs is more budget than that graph needs.
  • Embeddings are transductive: there is no way to embed a node that was not in the training graph without retraining.
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support