gpath2vec 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gpath2vec-3.0.0/LICENSE +21 -0
- gpath2vec-3.0.0/PKG-INFO +342 -0
- gpath2vec-3.0.0/README.md +292 -0
- gpath2vec-3.0.0/gpath2vec/__init__.py +10 -0
- gpath2vec-3.0.0/gpath2vec/aucell.py +274 -0
- gpath2vec-3.0.0/gpath2vec/cli.py +602 -0
- gpath2vec-3.0.0/gpath2vec/compare.py +86 -0
- gpath2vec-3.0.0/gpath2vec/ea.py +201 -0
- gpath2vec-3.0.0/gpath2vec/embedder.py +554 -0
- gpath2vec-3.0.0/gpath2vec/net.py +140 -0
- gpath2vec-3.0.0/gpath2vec/utils.py +124 -0
- gpath2vec-3.0.0/gpath2vec.egg-info/PKG-INFO +342 -0
- gpath2vec-3.0.0/gpath2vec.egg-info/SOURCES.txt +20 -0
- gpath2vec-3.0.0/gpath2vec.egg-info/dependency_links.txt +1 -0
- gpath2vec-3.0.0/gpath2vec.egg-info/entry_points.txt +2 -0
- gpath2vec-3.0.0/gpath2vec.egg-info/requires.txt +16 -0
- gpath2vec-3.0.0/gpath2vec.egg-info/top_level.txt +1 -0
- gpath2vec-3.0.0/setup.cfg +4 -0
- gpath2vec-3.0.0/setup.py +51 -0
- gpath2vec-3.0.0/tests/test_aucell_topk.py +71 -0
- gpath2vec-3.0.0/tests/test_ea_aggregation.py +72 -0
- gpath2vec-3.0.0/tests/test_metapath_topology.py +111 -0
gpath2vec-3.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nasim Sanati
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
gpath2vec-3.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gpath2vec
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: gene-set to biological pathway embeddings with enrichment analysis
|
|
5
|
+
Home-page: https://github.com/teslajoy/gpath2vec
|
|
6
|
+
Author: Nasim Sanati
|
|
7
|
+
Author-email: nasim@plenary.org
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/teslajoy/gpath2vec/issues
|
|
10
|
+
Project-URL: Source, https://github.com/teslajoy/gpath2vec
|
|
11
|
+
Keywords: bioinformatics pathways embeddings enrichment-analysis metapath2vec reactome
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: torch
|
|
23
|
+
Requires-Dist: networkx
|
|
24
|
+
Requires-Dist: requests
|
|
25
|
+
Requires-Dist: click
|
|
26
|
+
Requires-Dist: numpy
|
|
27
|
+
Requires-Dist: pandas
|
|
28
|
+
Requires-Dist: scipy
|
|
29
|
+
Requires-Dist: statsmodels
|
|
30
|
+
Requires-Dist: scikit-learn
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest; extra == "test"
|
|
33
|
+
Provides-Extra: aucell
|
|
34
|
+
Requires-Dist: decoupler>=2.1; extra == "aucell"
|
|
35
|
+
Requires-Dist: anndata; extra == "aucell"
|
|
36
|
+
Dynamic: author
|
|
37
|
+
Dynamic: author-email
|
|
38
|
+
Dynamic: classifier
|
|
39
|
+
Dynamic: description
|
|
40
|
+
Dynamic: description-content-type
|
|
41
|
+
Dynamic: home-page
|
|
42
|
+
Dynamic: keywords
|
|
43
|
+
Dynamic: license
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
Dynamic: project-url
|
|
46
|
+
Dynamic: provides-extra
|
|
47
|
+
Dynamic: requires-dist
|
|
48
|
+
Dynamic: requires-python
|
|
49
|
+
Dynamic: summary
|
|
50
|
+
|
|
51
|
+
# gpath2vec
|
|
52
|
+
|
|
53
|
+

|
|
54
|
+
[](https://opensource.org/licenses/MIT)
|
|
55
|
+
[](https://doi.org/10.5281/zenodo.22681141)
|
|
56
|
+
|
|
57
|
+
a python package for converting gene sets to biological pathway embeddings with enrichment analysis attributes.
|
|
58
|
+
|
|
59
|
+
gene sets (from clusters, niches, studies) are tested against reactome pathways via fisher's exact test, then embedded into a shared vector space using metapath2vec over the pathway hierarchy graph.
|
|
60
|
+
|
|
61
|
+
enrichment is either fisher's exact (a binary top-N gene set per cluster/niche) or **niche-level AUCell** (the full per-niche expression ranking, no gene-set selection step). AUCell here scores each niche's **aggregated pseudobulk** profile, one score per (niche, pathway); it is **not single-cell AUCell** (the package never sees individual cells, niche construction is upstream). both enrichment sources feed the same reactome hierarchy graph and metapath2vec embedding.
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
## pipeline
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
gene sets (per cluster/niche/study)
|
|
69
|
+
|
|
|
70
|
+
v
|
|
71
|
+
pathway filtering (level: high/mid/low, gene type: TF, etc.)
|
|
72
|
+
|
|
|
73
|
+
v
|
|
74
|
+
enrichment analysis (fisher's exact test, fdr correction)
|
|
75
|
+
|
|
|
76
|
+
v
|
|
77
|
+
EA matrix: cluster x pathway (1-fdr or odds ratio weights)
|
|
78
|
+
|
|
|
79
|
+
v
|
|
80
|
+
pathway hierarchy graph (reactome) + cluster nodes with EA edges
|
|
81
|
+
|
|
|
82
|
+
v
|
|
83
|
+
metapath2vec random walks (weighted, type-biased)
|
|
84
|
+
|
|
|
85
|
+
v
|
|
86
|
+
skipgram embeddings (default 512-d)
|
|
87
|
+
|
|
|
88
|
+
v
|
|
89
|
+
cluster x 512 embedding matrix
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## the network
|
|
93
|
+
|
|
94
|
+
the `Net` class builds a heterogeneous networkx graph with two node types:
|
|
95
|
+
|
|
96
|
+
- **pathway nodes** (reactome stIds): the reactome homo sapiens pathway hierarchy
|
|
97
|
+
- **cluster nodes** (your gene lists of interest): added from enrichment results
|
|
98
|
+
|
|
99
|
+
and two edge types:
|
|
100
|
+
|
|
101
|
+
- **pathway - pathway**: parent-child relations from the reactome hierarchy
|
|
102
|
+
- **cluster - pathway**: weighted edges from enrichment analysis (1 - fdr or odds ratio). each cluster connects to its significantly enriched pathways.
|
|
103
|
+
|
|
104
|
+
genes are not in the graph. they are used upstream in the enrichment step to determine which pathways are significant, but only pathways and clusters appear as nodes.
|
|
105
|
+
|
|
106
|
+
pathway node attributes:
|
|
107
|
+
|
|
108
|
+
- `node_type`: "sig" or "notsig" (fdr < 0.05)
|
|
109
|
+
- `het`: 1 (sig), 0 (notsig), or -1 (not in enrichment results)
|
|
110
|
+
- `feature`: fdr value (raw)
|
|
111
|
+
- `features`: [1 - fdr] (inverted, used as weight)
|
|
112
|
+
- `stId`: reactome stable identifier
|
|
113
|
+
- `pathway_name`: human-readable name
|
|
114
|
+
- `parent_pathway`: top-level reactome category
|
|
115
|
+
|
|
116
|
+
cluster node attributes:
|
|
117
|
+
|
|
118
|
+
- `node_type`: "cluster"
|
|
119
|
+
- `cluster`: cluster name
|
|
120
|
+
|
|
121
|
+
cluster-pathway edge attributes:
|
|
122
|
+
|
|
123
|
+
- `weight`: enrichment score (1 - fdr or odds ratio)
|
|
124
|
+
|
|
125
|
+
the graph can be filtered by pathway level (high/mid/low) and by gene membership before construction. set `digraph=True` for a directed graph, `induce=True` to keep only significant pathways.
|
|
126
|
+
|
|
127
|
+
## the embeddings
|
|
128
|
+
|
|
129
|
+
metapath2vec performs biased random walks on the network, then trains a skipgram model to learn a dense vector for every node.
|
|
130
|
+
|
|
131
|
+
the walks are type-aware: metapaths like `[sig, notsig, sig]` or `[cluster, sig, sig]` guide the walker to follow specific node-type sequences. edge weights from the enrichment analysis bias which neighbors get visited, so clusters with strong signal to specific pathways walk there more often.
|
|
132
|
+
|
|
133
|
+
the result is a shared embedding space where:
|
|
134
|
+
|
|
135
|
+
- **pathway embeddings** (`pathway x dim`) capture where each pathway sits in the reactome hierarchy and how it relates to other pathways through enrichment patterns. pathways that are structurally close in reactome or co-enriched across clusters end up with similar vectors.
|
|
136
|
+
- **cluster embeddings** (`cluster x dim`) capture each cluster's biological function as a position in pathway space. two clusters with similar pathway enrichment profiles end up close together, but unlike the raw EA matrix, the embedding also encodes the hierarchical relationships between their enriched pathways. a cluster enriched in "FGFR2 alternative splicing" and one enriched in "signaling by FGFR" will be closer than two clusters enriched in unrelated pathways, even if neither shares the exact same significant pathway.
|
|
137
|
+
- **EA matrix** (`cluster x pathway`) is the interpretable complement to the embeddings. each row is a cluster's pathway activity profile with explicit scores (1 - fdr or odds ratio). it serves as ground truth for what the embeddings encode and can be used directly for comparison across studies via cosine similarity.
|
|
138
|
+
|
|
139
|
+
## outputs
|
|
140
|
+
|
|
141
|
+
- **EA matrix** (`cluster x pathway`): enrichment weights per cluster, available as 1 - fdr or odds ratio
|
|
142
|
+
- **cluster embeddings** (`cluster x dim`): one dense vector per cluster encoding pathway activity + graph structure
|
|
143
|
+
- **pathway embeddings** (`pathway x dim`): one dense vector per pathway encoding hierarchical position + enrichment context
|
|
144
|
+
|
|
145
|
+
## install
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
pip install -e . # fisher enrichment path
|
|
149
|
+
pip install -e '.[aucell]' # adds the niche-level AUCell path (decoupler, anndata)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## usage
|
|
153
|
+
|
|
154
|
+
### python
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from gpath2vec.ea import enrich, ea_matrix, filter_pathways
|
|
158
|
+
from gpath2vec.net import Net
|
|
159
|
+
from gpath2vec.embedder import PathwayMetapath2vec
|
|
160
|
+
|
|
161
|
+
# gene sets: dict of {name: [genes]}
|
|
162
|
+
gene_sets = {
|
|
163
|
+
"cluster_0": ["EGFR", "EGF", "FGFR2", ...],
|
|
164
|
+
"cluster_1": ["CD8A", "CD8B", "GZMB", ...],
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
# enrichment (filter to low-level pathways containing TF genes)
|
|
168
|
+
ea_df = enrich(gene_sets, level="low", gene_filter=tf_genes)
|
|
169
|
+
matrix = ea_matrix(ea_df, weight="fdr") # cluster x pathway
|
|
170
|
+
matrix_or = ea_matrix(ea_df, weight="oddsratio")
|
|
171
|
+
|
|
172
|
+
# build graph with cluster nodes
|
|
173
|
+
clusters = {}
|
|
174
|
+
for _, r in ea_df[ea_df.sig_pathway].iterrows():
|
|
175
|
+
clusters.setdefault(r["cluster"], {})[r["stId"]] = 1 - r["fdr_bh"]
|
|
176
|
+
|
|
177
|
+
enrichment = [{"stId": r["stId"], "entities": {"fdr": r["fdr_bh"]}}
|
|
178
|
+
for _, r in ea_df.drop_duplicates("stId").iterrows()]
|
|
179
|
+
|
|
180
|
+
net = Net(enrichment=enrichment, id="my_study", digraph=True,
|
|
181
|
+
level="low", gene_filter=tf_genes, clusters=clusters)
|
|
182
|
+
|
|
183
|
+
# embeddings (pick a method)
|
|
184
|
+
from gpath2vec.embedder import (
|
|
185
|
+
PathwayMetapath2vec, SVDEmbedder, SpectralGraphEmbedder, LINEEmbedder
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# metapath2vec: weighted random walks + skipgram on the graph
|
|
189
|
+
embedder = PathwayMetapath2vec(graph=net.graph, name="my_study",
|
|
190
|
+
walks_per_node=10, walk_length=100)
|
|
191
|
+
walks = embedder.model
|
|
192
|
+
embedder.train_embeddings(walks=walks, dimensions=512, epochs=15, lr=0.005)
|
|
193
|
+
|
|
194
|
+
# svd: truncated svd on the ea matrix (no graph, baseline)
|
|
195
|
+
embedder = SVDEmbedder(matrix, dimensions=512)
|
|
196
|
+
|
|
197
|
+
# spectral: laplacian eigenmaps on the graph (deterministic)
|
|
198
|
+
embedder = SpectralGraphEmbedder(net.graph, dimensions=512)
|
|
199
|
+
|
|
200
|
+
# line: first + second order proximity on the graph (weighted edges)
|
|
201
|
+
embedder = LINEEmbedder(net.graph, dimensions=512, epochs=15, lr=0.005)
|
|
202
|
+
|
|
203
|
+
embeddings = embedder.get_embeddings()
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### cli
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# enrichment
|
|
210
|
+
gpath2vec enrichment --genes "EGFR,EGF,FGFR2" --level low --out-path results.json
|
|
211
|
+
|
|
212
|
+
# network
|
|
213
|
+
gpath2vec network --enrichment-path results.json --level low --out-path net.pkl
|
|
214
|
+
|
|
215
|
+
# embeddings (default: metapath2vec)
|
|
216
|
+
gpath2vec embeddings --network-path net.pkl --dimensions 512 --out-path emb.pkl
|
|
217
|
+
|
|
218
|
+
# embeddings with alternative methods
|
|
219
|
+
gpath2vec embeddings --network-path net.pkl --method svd --ea-matrix-path ea_matrix.csv --out-path emb.pkl
|
|
220
|
+
gpath2vec embeddings --network-path net.pkl --method spectral --out-path emb.pkl
|
|
221
|
+
gpath2vec embeddings --network-path net.pkl --method line --out-path emb.pkl
|
|
222
|
+
gpath2vec embeddings --network-path net.pkl --method vae --ea-matrix-path ea_matrix.csv --out-path emb.pkl
|
|
223
|
+
|
|
224
|
+
# full pipeline with method choice
|
|
225
|
+
gpath2vec end2end --genes "EGFR,EGF" --level low --method vae --output-dir output/
|
|
226
|
+
|
|
227
|
+
# niche pipeline: enrichment -> graph -> embeddings in one command.
|
|
228
|
+
# --enrichment fisher : binary top-N gene set per niche, fisher's exact + fdr.
|
|
229
|
+
# --enrichment aucell : niche-level AUCell on each niche's aggregated pseudobulk
|
|
230
|
+
# (one score per niche, NOT single-cell), per-niche top-k as edges.
|
|
231
|
+
# --aucell-standardize zscore : rank the per-niche top-k by cross-niche relative
|
|
232
|
+
# elevation, so pathways that are high in EVERY niche
|
|
233
|
+
# (the housekeeping floor) drop out. this is the cli
|
|
234
|
+
# default. the library `topk_per_niche()` still defaults
|
|
235
|
+
# to "none" (absolute score) for backward compatibility.
|
|
236
|
+
# inputs: --niche-matrix (niches x genes .npz/.npy), --genes (.npy gene order),
|
|
237
|
+
# --niche-meta (parquet with a niche_id column).
|
|
238
|
+
gpath2vec niche-pipeline \
|
|
239
|
+
--niche-matrix niches.npz --genes genes.npy --niche-meta niche_meta.parquet \
|
|
240
|
+
--enrichment aucell --reactome-level low --topk 50 \
|
|
241
|
+
--reactome-dir /path/to/reactome/cache --out-dir output/
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## embedding methods
|
|
245
|
+
|
|
246
|
+
| method | input | training | edge weights | deterministic |
|
|
247
|
+
|--------|-------|----------|-------------|---------------|
|
|
248
|
+
| metapath2vec | graph | skipgram on random walks | yes (biases walks) | no |
|
|
249
|
+
| svd | ea matrix | truncated svd | n/a (no graph) | yes |
|
|
250
|
+
| spectral | graph | laplacian eigenmaps | yes | yes |
|
|
251
|
+
| line | graph | first + second order proximity | yes (samples proportional) | no |
|
|
252
|
+
| vae | ea matrix | variational autoencoder | n/a (no graph) | no |
|
|
253
|
+
|
|
254
|
+
- **metapath2vec**: best for capturing heterogeneous graph structure (pathway hierarchy + cluster nodes). requires training.
|
|
255
|
+
- **svd**: baseline. operates on the ea matrix directly, no graph structure. fast, deterministic. if svd gives the same results as metapath2vec, the graph isn't adding signal.
|
|
256
|
+
- **spectral**: deterministic embedding from the graph laplacian. good comparison point for metapath2vec without training variance.
|
|
257
|
+
- **line**: handles edge weights more explicitly than metapath2vec. two objectives capture both local (direct neighbors) and global (shared neighbor) structure.
|
|
258
|
+
- **vae**: variational autoencoder on the ea matrix. smooth latent space where similar pathway profiles map nearby. provides uncertainty estimates (latent variance per cluster) and can generate new pathway activity profiles. nonlinear alternative to svd.
|
|
259
|
+
|
|
260
|
+
all methods are more configurable from python than the cli. for example, vae exposes `beta` (kl divergence weight), `hidden_dim`, and the full model for downstream use:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from gpath2vec.embedder import VAEEmbedder
|
|
264
|
+
|
|
265
|
+
vae = VAEEmbedder(ea_matrix, dimensions=512, beta=0.5, hidden_dim=256)
|
|
266
|
+
embeddings = vae.get_embeddings() # latent means
|
|
267
|
+
uncertainty = vae.get_uncertainty() # latent variance per cluster
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## pathway levels
|
|
271
|
+
|
|
272
|
+
pathway filtering uses reactome's own classification:
|
|
273
|
+
|
|
274
|
+
- **high**: pathways with enhanced high level diagrams (ehld)
|
|
275
|
+
- **mid**: pathways between ehld and sbgn
|
|
276
|
+
- **low**: pathways with sbgn diagrams (most specific)
|
|
277
|
+
- **all**: no filtering
|
|
278
|
+
|
|
279
|
+
## gene filtering
|
|
280
|
+
|
|
281
|
+
restrict the pathway universe to only pathways containing specific genes of interest (ex. transcription factors from pathway commons):
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
# TF genes from pathway commons SIF (controls-expression-of)
|
|
285
|
+
ea_df = enrich(gene_sets, level="low", gene_filter=tf_genes)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## local caching
|
|
289
|
+
|
|
290
|
+
reactome data is downloaded once and cached to `~/.gpath2vec/cache/`. set `GPATH2VEC_REACTOME_DIR` to use a custom cache directory:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
export GPATH2VEC_REACTOME_DIR=/path/to/reactome/files
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### offline / hpc (air-gapped compute nodes)
|
|
297
|
+
|
|
298
|
+
clusters like ARC have no internet on compute nodes, so the cache must be staged from a node that does have internet (ex. a login node):
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
./pull_reactome_cache.sh /shared/path/reactome_cache # run where there IS internet
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
this drives the package's real fetchers, so the cache matches exactly what gpath2vec expects. on the compute node, point at it without re-downloading:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
gpath2vec niche-pipeline ... --reactome-dir /shared/path/reactome_cache
|
|
308
|
+
# or: export GPATH2VEC_REACTOME_DIR=/shared/path/reactome_cache
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## reproducibility
|
|
312
|
+
|
|
313
|
+
all stochastic embedders (metapath2vec, line, vae) take a `seed` (default 1234) that pins the python, numpy and torch rngs, so embeddings are bit-reproducible run to run. the seed is re-applied before training (independent of walk-generation rng) and recorded in `run_provenance.json`. svd and spectral are deterministic by construction. cli: `--seed`.
|
|
314
|
+
|
|
315
|
+
## citation
|
|
316
|
+
|
|
317
|
+
archived on zenodo. the DOI below is the *concept* DOI: it always resolves to
|
|
318
|
+
the newest release, so it stays correct as versions are added.
|
|
319
|
+
|
|
320
|
+
> Sanati, N. (2026). *gpath2vec: Pathway-Informed Feature Embeddings for
|
|
321
|
+
> Biological Observations from Gene Sets*. Zenodo.
|
|
322
|
+
> https://doi.org/10.5281/zenodo.22681141
|
|
323
|
+
|
|
324
|
+
```bibtex
|
|
325
|
+
@software{sanati_gpath2vec,
|
|
326
|
+
author = {Sanati, Nasim},
|
|
327
|
+
title = {{gpath2vec: Pathway-Informed Feature Embeddings for
|
|
328
|
+
Biological Observations from Gene Sets}},
|
|
329
|
+
year = {2026},
|
|
330
|
+
publisher = {Zenodo},
|
|
331
|
+
doi = {10.5281/zenodo.22681141},
|
|
332
|
+
url = {https://doi.org/10.5281/zenodo.22681141}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
to cite the exact snapshot rather than the latest release, use the version DOI
|
|
337
|
+
for v3.0.0: `10.5281/zenodo.22681142`.
|
|
338
|
+
|
|
339
|
+
## todo
|
|
340
|
+
|
|
341
|
+
- **edge2vec**: edge-type transition-matrix biased walks as an embedding method.
|
|
342
|
+
- **lorentz (hyperbolic) pipeline**
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# gpath2vec
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://doi.org/10.5281/zenodo.22681141)
|
|
6
|
+
|
|
7
|
+
a python package for converting gene sets to biological pathway embeddings with enrichment analysis attributes.
|
|
8
|
+
|
|
9
|
+
gene sets (from clusters, niches, studies) are tested against reactome pathways via fisher's exact test, then embedded into a shared vector space using metapath2vec over the pathway hierarchy graph.
|
|
10
|
+
|
|
11
|
+
enrichment is either fisher's exact (a binary top-N gene set per cluster/niche) or **niche-level AUCell** (the full per-niche expression ranking, no gene-set selection step). AUCell here scores each niche's **aggregated pseudobulk** profile, one score per (niche, pathway); it is **not single-cell AUCell** (the package never sees individual cells, niche construction is upstream). both enrichment sources feed the same reactome hierarchy graph and metapath2vec embedding.
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
## pipeline
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
gene sets (per cluster/niche/study)
|
|
19
|
+
|
|
|
20
|
+
v
|
|
21
|
+
pathway filtering (level: high/mid/low, gene type: TF, etc.)
|
|
22
|
+
|
|
|
23
|
+
v
|
|
24
|
+
enrichment analysis (fisher's exact test, fdr correction)
|
|
25
|
+
|
|
|
26
|
+
v
|
|
27
|
+
EA matrix: cluster x pathway (1-fdr or odds ratio weights)
|
|
28
|
+
|
|
|
29
|
+
v
|
|
30
|
+
pathway hierarchy graph (reactome) + cluster nodes with EA edges
|
|
31
|
+
|
|
|
32
|
+
v
|
|
33
|
+
metapath2vec random walks (weighted, type-biased)
|
|
34
|
+
|
|
|
35
|
+
v
|
|
36
|
+
skipgram embeddings (default 512-d)
|
|
37
|
+
|
|
|
38
|
+
v
|
|
39
|
+
cluster x 512 embedding matrix
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## the network
|
|
43
|
+
|
|
44
|
+
the `Net` class builds a heterogeneous networkx graph with two node types:
|
|
45
|
+
|
|
46
|
+
- **pathway nodes** (reactome stIds): the reactome homo sapiens pathway hierarchy
|
|
47
|
+
- **cluster nodes** (your gene lists of interest): added from enrichment results
|
|
48
|
+
|
|
49
|
+
and two edge types:
|
|
50
|
+
|
|
51
|
+
- **pathway - pathway**: parent-child relations from the reactome hierarchy
|
|
52
|
+
- **cluster - pathway**: weighted edges from enrichment analysis (1 - fdr or odds ratio). each cluster connects to its significantly enriched pathways.
|
|
53
|
+
|
|
54
|
+
genes are not in the graph. they are used upstream in the enrichment step to determine which pathways are significant, but only pathways and clusters appear as nodes.
|
|
55
|
+
|
|
56
|
+
pathway node attributes:
|
|
57
|
+
|
|
58
|
+
- `node_type`: "sig" or "notsig" (fdr < 0.05)
|
|
59
|
+
- `het`: 1 (sig), 0 (notsig), or -1 (not in enrichment results)
|
|
60
|
+
- `feature`: fdr value (raw)
|
|
61
|
+
- `features`: [1 - fdr] (inverted, used as weight)
|
|
62
|
+
- `stId`: reactome stable identifier
|
|
63
|
+
- `pathway_name`: human-readable name
|
|
64
|
+
- `parent_pathway`: top-level reactome category
|
|
65
|
+
|
|
66
|
+
cluster node attributes:
|
|
67
|
+
|
|
68
|
+
- `node_type`: "cluster"
|
|
69
|
+
- `cluster`: cluster name
|
|
70
|
+
|
|
71
|
+
cluster-pathway edge attributes:
|
|
72
|
+
|
|
73
|
+
- `weight`: enrichment score (1 - fdr or odds ratio)
|
|
74
|
+
|
|
75
|
+
the graph can be filtered by pathway level (high/mid/low) and by gene membership before construction. set `digraph=True` for a directed graph, `induce=True` to keep only significant pathways.
|
|
76
|
+
|
|
77
|
+
## the embeddings
|
|
78
|
+
|
|
79
|
+
metapath2vec performs biased random walks on the network, then trains a skipgram model to learn a dense vector for every node.
|
|
80
|
+
|
|
81
|
+
the walks are type-aware: metapaths like `[sig, notsig, sig]` or `[cluster, sig, sig]` guide the walker to follow specific node-type sequences. edge weights from the enrichment analysis bias which neighbors get visited, so clusters with strong signal to specific pathways walk there more often.
|
|
82
|
+
|
|
83
|
+
the result is a shared embedding space where:
|
|
84
|
+
|
|
85
|
+
- **pathway embeddings** (`pathway x dim`) capture where each pathway sits in the reactome hierarchy and how it relates to other pathways through enrichment patterns. pathways that are structurally close in reactome or co-enriched across clusters end up with similar vectors.
|
|
86
|
+
- **cluster embeddings** (`cluster x dim`) capture each cluster's biological function as a position in pathway space. two clusters with similar pathway enrichment profiles end up close together, but unlike the raw EA matrix, the embedding also encodes the hierarchical relationships between their enriched pathways. a cluster enriched in "FGFR2 alternative splicing" and one enriched in "signaling by FGFR" will be closer than two clusters enriched in unrelated pathways, even if neither shares the exact same significant pathway.
|
|
87
|
+
- **EA matrix** (`cluster x pathway`) is the interpretable complement to the embeddings. each row is a cluster's pathway activity profile with explicit scores (1 - fdr or odds ratio). it serves as ground truth for what the embeddings encode and can be used directly for comparison across studies via cosine similarity.
|
|
88
|
+
|
|
89
|
+
## outputs
|
|
90
|
+
|
|
91
|
+
- **EA matrix** (`cluster x pathway`): enrichment weights per cluster, available as 1 - fdr or odds ratio
|
|
92
|
+
- **cluster embeddings** (`cluster x dim`): one dense vector per cluster encoding pathway activity + graph structure
|
|
93
|
+
- **pathway embeddings** (`pathway x dim`): one dense vector per pathway encoding hierarchical position + enrichment context
|
|
94
|
+
|
|
95
|
+
## install
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install -e . # fisher enrichment path
|
|
99
|
+
pip install -e '.[aucell]' # adds the niche-level AUCell path (decoupler, anndata)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## usage
|
|
103
|
+
|
|
104
|
+
### python
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
from gpath2vec.ea import enrich, ea_matrix, filter_pathways
|
|
108
|
+
from gpath2vec.net import Net
|
|
109
|
+
from gpath2vec.embedder import PathwayMetapath2vec
|
|
110
|
+
|
|
111
|
+
# gene sets: dict of {name: [genes]}
|
|
112
|
+
gene_sets = {
|
|
113
|
+
"cluster_0": ["EGFR", "EGF", "FGFR2", ...],
|
|
114
|
+
"cluster_1": ["CD8A", "CD8B", "GZMB", ...],
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
# enrichment (filter to low-level pathways containing TF genes)
|
|
118
|
+
ea_df = enrich(gene_sets, level="low", gene_filter=tf_genes)
|
|
119
|
+
matrix = ea_matrix(ea_df, weight="fdr") # cluster x pathway
|
|
120
|
+
matrix_or = ea_matrix(ea_df, weight="oddsratio")
|
|
121
|
+
|
|
122
|
+
# build graph with cluster nodes
|
|
123
|
+
clusters = {}
|
|
124
|
+
for _, r in ea_df[ea_df.sig_pathway].iterrows():
|
|
125
|
+
clusters.setdefault(r["cluster"], {})[r["stId"]] = 1 - r["fdr_bh"]
|
|
126
|
+
|
|
127
|
+
enrichment = [{"stId": r["stId"], "entities": {"fdr": r["fdr_bh"]}}
|
|
128
|
+
for _, r in ea_df.drop_duplicates("stId").iterrows()]
|
|
129
|
+
|
|
130
|
+
net = Net(enrichment=enrichment, id="my_study", digraph=True,
|
|
131
|
+
level="low", gene_filter=tf_genes, clusters=clusters)
|
|
132
|
+
|
|
133
|
+
# embeddings (pick a method)
|
|
134
|
+
from gpath2vec.embedder import (
|
|
135
|
+
PathwayMetapath2vec, SVDEmbedder, SpectralGraphEmbedder, LINEEmbedder
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# metapath2vec: weighted random walks + skipgram on the graph
|
|
139
|
+
embedder = PathwayMetapath2vec(graph=net.graph, name="my_study",
|
|
140
|
+
walks_per_node=10, walk_length=100)
|
|
141
|
+
walks = embedder.model
|
|
142
|
+
embedder.train_embeddings(walks=walks, dimensions=512, epochs=15, lr=0.005)
|
|
143
|
+
|
|
144
|
+
# svd: truncated svd on the ea matrix (no graph, baseline)
|
|
145
|
+
embedder = SVDEmbedder(matrix, dimensions=512)
|
|
146
|
+
|
|
147
|
+
# spectral: laplacian eigenmaps on the graph (deterministic)
|
|
148
|
+
embedder = SpectralGraphEmbedder(net.graph, dimensions=512)
|
|
149
|
+
|
|
150
|
+
# line: first + second order proximity on the graph (weighted edges)
|
|
151
|
+
embedder = LINEEmbedder(net.graph, dimensions=512, epochs=15, lr=0.005)
|
|
152
|
+
|
|
153
|
+
embeddings = embedder.get_embeddings()
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### cli
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# enrichment
|
|
160
|
+
gpath2vec enrichment --genes "EGFR,EGF,FGFR2" --level low --out-path results.json
|
|
161
|
+
|
|
162
|
+
# network
|
|
163
|
+
gpath2vec network --enrichment-path results.json --level low --out-path net.pkl
|
|
164
|
+
|
|
165
|
+
# embeddings (default: metapath2vec)
|
|
166
|
+
gpath2vec embeddings --network-path net.pkl --dimensions 512 --out-path emb.pkl
|
|
167
|
+
|
|
168
|
+
# embeddings with alternative methods
|
|
169
|
+
gpath2vec embeddings --network-path net.pkl --method svd --ea-matrix-path ea_matrix.csv --out-path emb.pkl
|
|
170
|
+
gpath2vec embeddings --network-path net.pkl --method spectral --out-path emb.pkl
|
|
171
|
+
gpath2vec embeddings --network-path net.pkl --method line --out-path emb.pkl
|
|
172
|
+
gpath2vec embeddings --network-path net.pkl --method vae --ea-matrix-path ea_matrix.csv --out-path emb.pkl
|
|
173
|
+
|
|
174
|
+
# full pipeline with method choice
|
|
175
|
+
gpath2vec end2end --genes "EGFR,EGF" --level low --method vae --output-dir output/
|
|
176
|
+
|
|
177
|
+
# niche pipeline: enrichment -> graph -> embeddings in one command.
|
|
178
|
+
# --enrichment fisher : binary top-N gene set per niche, fisher's exact + fdr.
|
|
179
|
+
# --enrichment aucell : niche-level AUCell on each niche's aggregated pseudobulk
|
|
180
|
+
# (one score per niche, NOT single-cell), per-niche top-k as edges.
|
|
181
|
+
# --aucell-standardize zscore : rank the per-niche top-k by cross-niche relative
|
|
182
|
+
# elevation, so pathways that are high in EVERY niche
|
|
183
|
+
# (the housekeeping floor) drop out. this is the cli
|
|
184
|
+
# default. the library `topk_per_niche()` still defaults
|
|
185
|
+
# to "none" (absolute score) for backward compatibility.
|
|
186
|
+
# inputs: --niche-matrix (niches x genes .npz/.npy), --genes (.npy gene order),
|
|
187
|
+
# --niche-meta (parquet with a niche_id column).
|
|
188
|
+
gpath2vec niche-pipeline \
|
|
189
|
+
--niche-matrix niches.npz --genes genes.npy --niche-meta niche_meta.parquet \
|
|
190
|
+
--enrichment aucell --reactome-level low --topk 50 \
|
|
191
|
+
--reactome-dir /path/to/reactome/cache --out-dir output/
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## embedding methods
|
|
195
|
+
|
|
196
|
+
| method | input | training | edge weights | deterministic |
|
|
197
|
+
|--------|-------|----------|-------------|---------------|
|
|
198
|
+
| metapath2vec | graph | skipgram on random walks | yes (biases walks) | no |
|
|
199
|
+
| svd | ea matrix | truncated svd | n/a (no graph) | yes |
|
|
200
|
+
| spectral | graph | laplacian eigenmaps | yes | yes |
|
|
201
|
+
| line | graph | first + second order proximity | yes (samples proportional) | no |
|
|
202
|
+
| vae | ea matrix | variational autoencoder | n/a (no graph) | no |
|
|
203
|
+
|
|
204
|
+
- **metapath2vec**: best for capturing heterogeneous graph structure (pathway hierarchy + cluster nodes). requires training.
|
|
205
|
+
- **svd**: baseline. operates on the ea matrix directly, no graph structure. fast, deterministic. if svd gives the same results as metapath2vec, the graph isn't adding signal.
|
|
206
|
+
- **spectral**: deterministic embedding from the graph laplacian. good comparison point for metapath2vec without training variance.
|
|
207
|
+
- **line**: handles edge weights more explicitly than metapath2vec. two objectives capture both local (direct neighbors) and global (shared neighbor) structure.
|
|
208
|
+
- **vae**: variational autoencoder on the ea matrix. smooth latent space where similar pathway profiles map nearby. provides uncertainty estimates (latent variance per cluster) and can generate new pathway activity profiles. nonlinear alternative to svd.
|
|
209
|
+
|
|
210
|
+
all methods are more configurable from python than the cli. for example, vae exposes `beta` (kl divergence weight), `hidden_dim`, and the full model for downstream use:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from gpath2vec.embedder import VAEEmbedder
|
|
214
|
+
|
|
215
|
+
vae = VAEEmbedder(ea_matrix, dimensions=512, beta=0.5, hidden_dim=256)
|
|
216
|
+
embeddings = vae.get_embeddings() # latent means
|
|
217
|
+
uncertainty = vae.get_uncertainty() # latent variance per cluster
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## pathway levels
|
|
221
|
+
|
|
222
|
+
pathway filtering uses reactome's own classification:
|
|
223
|
+
|
|
224
|
+
- **high**: pathways with enhanced high level diagrams (ehld)
|
|
225
|
+
- **mid**: pathways between ehld and sbgn
|
|
226
|
+
- **low**: pathways with sbgn diagrams (most specific)
|
|
227
|
+
- **all**: no filtering
|
|
228
|
+
|
|
229
|
+
## gene filtering
|
|
230
|
+
|
|
231
|
+
restrict the pathway universe to only pathways containing specific genes of interest (ex. transcription factors from pathway commons):
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
# TF genes from pathway commons SIF (controls-expression-of)
|
|
235
|
+
ea_df = enrich(gene_sets, level="low", gene_filter=tf_genes)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## local caching
|
|
239
|
+
|
|
240
|
+
reactome data is downloaded once and cached to `~/.gpath2vec/cache/`. set `GPATH2VEC_REACTOME_DIR` to use a custom cache directory:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
export GPATH2VEC_REACTOME_DIR=/path/to/reactome/files
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### offline / hpc (air-gapped compute nodes)
|
|
247
|
+
|
|
248
|
+
clusters like ARC have no internet on compute nodes, so the cache must be staged from a node that does have internet (ex. a login node):
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
./pull_reactome_cache.sh /shared/path/reactome_cache # run where there IS internet
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
this drives the package's real fetchers, so the cache matches exactly what gpath2vec expects. on the compute node, point at it without re-downloading:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
gpath2vec niche-pipeline ... --reactome-dir /shared/path/reactome_cache
|
|
258
|
+
# or: export GPATH2VEC_REACTOME_DIR=/shared/path/reactome_cache
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## reproducibility
|
|
262
|
+
|
|
263
|
+
all stochastic embedders (metapath2vec, line, vae) take a `seed` (default 1234) that pins the python, numpy and torch rngs, so embeddings are bit-reproducible run to run. the seed is re-applied before training (independent of walk-generation rng) and recorded in `run_provenance.json`. svd and spectral are deterministic by construction. cli: `--seed`.
|
|
264
|
+
|
|
265
|
+
## citation
|
|
266
|
+
|
|
267
|
+
archived on zenodo. the DOI below is the *concept* DOI: it always resolves to
|
|
268
|
+
the newest release, so it stays correct as versions are added.
|
|
269
|
+
|
|
270
|
+
> Sanati, N. (2026). *gpath2vec: Pathway-Informed Feature Embeddings for
|
|
271
|
+
> Biological Observations from Gene Sets*. Zenodo.
|
|
272
|
+
> https://doi.org/10.5281/zenodo.22681141
|
|
273
|
+
|
|
274
|
+
```bibtex
|
|
275
|
+
@software{sanati_gpath2vec,
|
|
276
|
+
author = {Sanati, Nasim},
|
|
277
|
+
title = {{gpath2vec: Pathway-Informed Feature Embeddings for
|
|
278
|
+
Biological Observations from Gene Sets}},
|
|
279
|
+
year = {2026},
|
|
280
|
+
publisher = {Zenodo},
|
|
281
|
+
doi = {10.5281/zenodo.22681141},
|
|
282
|
+
url = {https://doi.org/10.5281/zenodo.22681141}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
to cite the exact snapshot rather than the latest release, use the version DOI
|
|
287
|
+
for v3.0.0: `10.5281/zenodo.22681142`.
|
|
288
|
+
|
|
289
|
+
## todo
|
|
290
|
+
|
|
291
|
+
- **edge2vec**: edge-type transition-matrix biased walks as an embedding method.
|
|
292
|
+
- **lorentz (hyperbolic) pipeline**
|