bayesprism 0.1.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.
- bayesprism-0.1.0/LICENSE +21 -0
- bayesprism-0.1.0/PKG-INFO +120 -0
- bayesprism-0.1.0/README.md +87 -0
- bayesprism-0.1.0/pyproject.toml +45 -0
- bayesprism-0.1.0/setup.cfg +4 -0
- bayesprism-0.1.0/src/bayesprism/__init__.py +53 -0
- bayesprism-0.1.0/src/bayesprism/embedding.py +146 -0
- bayesprism-0.1.0/src/bayesprism/gibbs.py +296 -0
- bayesprism-0.1.0/src/bayesprism/models.py +146 -0
- bayesprism-0.1.0/src/bayesprism/optimization.py +254 -0
- bayesprism-0.1.0/src/bayesprism/pipeline.py +345 -0
- bayesprism-0.1.0/src/bayesprism/plotting.py +58 -0
- bayesprism-0.1.0/src/bayesprism/preprocessing.py +104 -0
- bayesprism-0.1.0/src/bayesprism/validation.py +65 -0
- bayesprism-0.1.0/src/bayesprism.egg-info/PKG-INFO +120 -0
- bayesprism-0.1.0/src/bayesprism.egg-info/SOURCES.txt +22 -0
- bayesprism-0.1.0/src/bayesprism.egg-info/dependency_links.txt +1 -0
- bayesprism-0.1.0/src/bayesprism.egg-info/requires.txt +9 -0
- bayesprism-0.1.0/src/bayesprism.egg-info/top_level.txt +1 -0
- bayesprism-0.1.0/tests/test_gibbs.py +39 -0
- bayesprism-0.1.0/tests/test_pipeline.py +79 -0
- bayesprism-0.1.0/tests/test_r_equivalence.py +46 -0
- bayesprism-0.1.0/tests/test_sparse.py +34 -0
- bayesprism-0.1.0/tests/test_validation.py +47 -0
bayesprism-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LuJoHae
|
|
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.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bayesprism
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pure Functional Python / PyTorch implementation of BayesPrism for Bayesian cell type and gene expression deconvolution
|
|
5
|
+
Author: LuJoHae
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/LuJoHae/bayesprism-python
|
|
8
|
+
Project-URL: Repository, https://github.com/LuJoHae/bayesprism-python
|
|
9
|
+
Project-URL: Issues, https://github.com/LuJoHae/bayesprism-python/issues
|
|
10
|
+
Keywords: bioinformatics,deconvolution,single-cell,bayesprism,pytorch,rna-seq
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: torch>=2.0.0
|
|
24
|
+
Requires-Dist: polars>=0.20.0
|
|
25
|
+
Requires-Dist: scipy>=1.10.0
|
|
26
|
+
Requires-Dist: numpy>=1.24.0
|
|
27
|
+
Requires-Dist: pydantic>=2.5.0
|
|
28
|
+
Requires-Dist: returns>=0.22.0
|
|
29
|
+
Requires-Dist: altair>=5.0.0
|
|
30
|
+
Requires-Dist: vl-convert-python>=1.0.0
|
|
31
|
+
Requires-Dist: scikit-learn>=1.3.0
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# BayesPrism (Python)
|
|
35
|
+
|
|
36
|
+
A pure functional Python and PyTorch implementation of **BayesPrism** for Bayesian cell type and gene expression deconvolution using single-cell RNA-seq references.
|
|
37
|
+
|
|
38
|
+
[](https://opensource.org/licenses/MIT)
|
|
39
|
+
[](https://www.python.org/downloads/)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Overview
|
|
44
|
+
|
|
45
|
+
BayesPrism infers the cellular composition and cell-type-specific gene expression profiles of heterogeneous bulk RNA-seq data by leveraging single-cell transcriptomics as a prior.
|
|
46
|
+
|
|
47
|
+
This package is a high-performance Python port built upon:
|
|
48
|
+
- **PyTorch** for accelerated matrix computations and GPU tensor operations.
|
|
49
|
+
- **Polars** for fast, declarative data processing.
|
|
50
|
+
- **Pure Functional Design** ensuring immutable state transitions, railway-oriented error handling via `returns`, and strict type safety.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install bayesprism
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or install directly from GitHub:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install git+https://github.com/LuJoHae/bayesprism-python.git
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import numpy as np
|
|
72
|
+
from bayesprism import new_prism, run_prism, get_fraction, get_exp
|
|
73
|
+
|
|
74
|
+
# 1. Prepare raw count matrices (samples x genes, cell_types x genes)
|
|
75
|
+
# Bulk mixture: X (samples x genes)
|
|
76
|
+
# scRNA-seq reference: phi_ref (cell_types x genes)
|
|
77
|
+
gene_names = ("CD3D", "CD8A", "CD4", "MS4A1", "CD68", ...)
|
|
78
|
+
|
|
79
|
+
# 2. Initialize the Prism model container
|
|
80
|
+
prism_result = new_prism(
|
|
81
|
+
X_bulk=X_bulk_counts,
|
|
82
|
+
phi_ref=phi_sc_reference,
|
|
83
|
+
gene_names=gene_names,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Unwrap monadic Result safely
|
|
87
|
+
prism = prism_result.unwrap()
|
|
88
|
+
|
|
89
|
+
# 3. Run Bayesian MCMC deconvolution
|
|
90
|
+
fitted_prism = run_prism(prism)
|
|
91
|
+
|
|
92
|
+
# 4. Extract inferred cell type fractions (theta)
|
|
93
|
+
fractions = get_fraction(fitted_prism)
|
|
94
|
+
|
|
95
|
+
# 5. Extract cell-type-specific expression profiles (Z)
|
|
96
|
+
expression_profiles = get_exp(fitted_prism)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Key Features
|
|
102
|
+
|
|
103
|
+
- **Bayesian Joint Estimation**: Jointly infers cell-type proportions ($\theta$) and cell-type-specific gene expression ($Z$).
|
|
104
|
+
- **Linear Count Space**: Operates directly on unnormalized raw sequencing counts to preserve count distributions without log-transformation artifacts.
|
|
105
|
+
- **Batched GPU Acceleration**: PyTorch tensors enable fast vectorized updates across large patient cohorts.
|
|
106
|
+
- **Modular Pipeline**: Full functional pipeline with separate Gibbs sampling, Nelder-Mead reference updating, and NMF embedding learning.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Citation & Acknowledgments
|
|
111
|
+
|
|
112
|
+
If you use BayesPrism in your research, please cite the original BayesPrism methodology:
|
|
113
|
+
|
|
114
|
+
> Chu, T., Wang, Z., Pe'er, D., & Danko, C. G. (2022). Cell type and gene expression deconvolution with BayesPrism. *Nature Cancer*, 3(4), 505-517. [doi:10.1038/s43018-022-00356-3](https://doi.org/10.1038/s43018-022-00356-3)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# BayesPrism (Python)
|
|
2
|
+
|
|
3
|
+
A pure functional Python and PyTorch implementation of **BayesPrism** for Bayesian cell type and gene expression deconvolution using single-cell RNA-seq references.
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.python.org/downloads/)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
BayesPrism infers the cellular composition and cell-type-specific gene expression profiles of heterogeneous bulk RNA-seq data by leveraging single-cell transcriptomics as a prior.
|
|
13
|
+
|
|
14
|
+
This package is a high-performance Python port built upon:
|
|
15
|
+
- **PyTorch** for accelerated matrix computations and GPU tensor operations.
|
|
16
|
+
- **Polars** for fast, declarative data processing.
|
|
17
|
+
- **Pure Functional Design** ensuring immutable state transitions, railway-oriented error handling via `returns`, and strict type safety.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install bayesprism
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Or install directly from GitHub:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install git+https://github.com/LuJoHae/bayesprism-python.git
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import numpy as np
|
|
39
|
+
from bayesprism import new_prism, run_prism, get_fraction, get_exp
|
|
40
|
+
|
|
41
|
+
# 1. Prepare raw count matrices (samples x genes, cell_types x genes)
|
|
42
|
+
# Bulk mixture: X (samples x genes)
|
|
43
|
+
# scRNA-seq reference: phi_ref (cell_types x genes)
|
|
44
|
+
gene_names = ("CD3D", "CD8A", "CD4", "MS4A1", "CD68", ...)
|
|
45
|
+
|
|
46
|
+
# 2. Initialize the Prism model container
|
|
47
|
+
prism_result = new_prism(
|
|
48
|
+
X_bulk=X_bulk_counts,
|
|
49
|
+
phi_ref=phi_sc_reference,
|
|
50
|
+
gene_names=gene_names,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Unwrap monadic Result safely
|
|
54
|
+
prism = prism_result.unwrap()
|
|
55
|
+
|
|
56
|
+
# 3. Run Bayesian MCMC deconvolution
|
|
57
|
+
fitted_prism = run_prism(prism)
|
|
58
|
+
|
|
59
|
+
# 4. Extract inferred cell type fractions (theta)
|
|
60
|
+
fractions = get_fraction(fitted_prism)
|
|
61
|
+
|
|
62
|
+
# 5. Extract cell-type-specific expression profiles (Z)
|
|
63
|
+
expression_profiles = get_exp(fitted_prism)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Key Features
|
|
69
|
+
|
|
70
|
+
- **Bayesian Joint Estimation**: Jointly infers cell-type proportions ($\theta$) and cell-type-specific gene expression ($Z$).
|
|
71
|
+
- **Linear Count Space**: Operates directly on unnormalized raw sequencing counts to preserve count distributions without log-transformation artifacts.
|
|
72
|
+
- **Batched GPU Acceleration**: PyTorch tensors enable fast vectorized updates across large patient cohorts.
|
|
73
|
+
- **Modular Pipeline**: Full functional pipeline with separate Gibbs sampling, Nelder-Mead reference updating, and NMF embedding learning.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Citation & Acknowledgments
|
|
78
|
+
|
|
79
|
+
If you use BayesPrism in your research, please cite the original BayesPrism methodology:
|
|
80
|
+
|
|
81
|
+
> Chu, T., Wang, Z., Pe'er, D., & Danko, C. G. (2022). Cell type and gene expression deconvolution with BayesPrism. *Nature Cancer*, 3(4), 505-517. [doi:10.1038/s43018-022-00356-3](https://doi.org/10.1038/s43018-022-00356-3)
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "bayesprism"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Pure Functional Python / PyTorch implementation of BayesPrism for Bayesian cell type and gene expression deconvolution"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "LuJoHae" }
|
|
9
|
+
]
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
keywords = ["bioinformatics", "deconvolution", "single-cell", "bayesprism", "pytorch", "rna-seq"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Science/Research",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.10",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"torch>=2.0.0",
|
|
25
|
+
"polars>=0.20.0",
|
|
26
|
+
"scipy>=1.10.0",
|
|
27
|
+
"numpy>=1.24.0",
|
|
28
|
+
"pydantic>=2.5.0",
|
|
29
|
+
"returns>=0.22.0",
|
|
30
|
+
"altair>=5.0.0",
|
|
31
|
+
"vl-convert-python>=1.0.0",
|
|
32
|
+
"scikit-learn>=1.3.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/LuJoHae/bayesprism-python"
|
|
37
|
+
Repository = "https://github.com/LuJoHae/bayesprism-python"
|
|
38
|
+
Issues = "https://github.com/LuJoHae/bayesprism-python/issues"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["setuptools>=61.0"]
|
|
42
|
+
build-backend = "setuptools.build_meta"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from bayesprism.models import (
|
|
2
|
+
RefPhi,
|
|
3
|
+
RefTumor,
|
|
4
|
+
Prism,
|
|
5
|
+
GibbsControl,
|
|
6
|
+
OptControl,
|
|
7
|
+
JointPost,
|
|
8
|
+
ThetaPost,
|
|
9
|
+
BayesPrism,
|
|
10
|
+
BayesPrismST,
|
|
11
|
+
)
|
|
12
|
+
from bayesprism.validation import validate_input
|
|
13
|
+
from bayesprism.preprocessing import norm_to_one, collapse, filter_bulk_outlier
|
|
14
|
+
from bayesprism.gibbs import run_gibbs, rdirichlet
|
|
15
|
+
from bayesprism.optimization import update_reference, transform_phi_t
|
|
16
|
+
from bayesprism.embedding import learn_embedding_nmf, run_EM
|
|
17
|
+
from bayesprism.pipeline import (
|
|
18
|
+
new_prism,
|
|
19
|
+
run_prism,
|
|
20
|
+
run_prism_st,
|
|
21
|
+
get_fraction,
|
|
22
|
+
get_exp,
|
|
23
|
+
)
|
|
24
|
+
from bayesprism.plotting import plot_cor_phi, export_chart_svg
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"RefPhi",
|
|
28
|
+
"RefTumor",
|
|
29
|
+
"Prism",
|
|
30
|
+
"GibbsControl",
|
|
31
|
+
"OptControl",
|
|
32
|
+
"JointPost",
|
|
33
|
+
"ThetaPost",
|
|
34
|
+
"BayesPrism",
|
|
35
|
+
"BayesPrismST",
|
|
36
|
+
"validate_input",
|
|
37
|
+
"norm_to_one",
|
|
38
|
+
"collapse",
|
|
39
|
+
"filter_bulk_outlier",
|
|
40
|
+
"run_gibbs",
|
|
41
|
+
"rdirichlet",
|
|
42
|
+
"update_reference",
|
|
43
|
+
"transform_phi_t",
|
|
44
|
+
"learn_embedding_nmf",
|
|
45
|
+
"run_EM",
|
|
46
|
+
"new_prism",
|
|
47
|
+
"run_prism",
|
|
48
|
+
"run_prism_st",
|
|
49
|
+
"get_fraction",
|
|
50
|
+
"get_exp",
|
|
51
|
+
"plot_cor_phi",
|
|
52
|
+
"export_chart_svg",
|
|
53
|
+
]
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from typing import Any, Union
|
|
2
|
+
import numpy as np
|
|
3
|
+
import torch
|
|
4
|
+
from sklearn.decomposition import NMF
|
|
5
|
+
from returns.result import Result, Success, Failure
|
|
6
|
+
from returns.maybe import Maybe, Some, Nothing
|
|
7
|
+
|
|
8
|
+
from bayesprism.models import (
|
|
9
|
+
BayesPrism,
|
|
10
|
+
RefTumor,
|
|
11
|
+
GibbsControl,
|
|
12
|
+
OptControl,
|
|
13
|
+
NmfControl,
|
|
14
|
+
)
|
|
15
|
+
from bayesprism.preprocessing import norm_to_one
|
|
16
|
+
from bayesprism.optimization import optimize_psi_map
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def compute_elbo(
|
|
20
|
+
opt_value: float,
|
|
21
|
+
psi_env: np.ndarray,
|
|
22
|
+
joint_post_z: torch.Tensor,
|
|
23
|
+
gibbs_constant: float,
|
|
24
|
+
) -> float:
|
|
25
|
+
"""Compute Evidence Lower Bound (ELBO) for Gibbs-EM convergence monitoring."""
|
|
26
|
+
Z_gk_env = joint_post_z.sum(dim=0).detach().cpu().numpy()
|
|
27
|
+
elbo_env = -float(np.sum(np.log(np.maximum(psi_env, 1e-12)) * Z_gk_env))
|
|
28
|
+
elbo = opt_value + elbo_env - gibbs_constant
|
|
29
|
+
return elbo
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run_EM(
|
|
33
|
+
eta_prior: np.ndarray,
|
|
34
|
+
psi_env: np.ndarray,
|
|
35
|
+
theta_env: np.ndarray,
|
|
36
|
+
X: np.ndarray,
|
|
37
|
+
cycle: int,
|
|
38
|
+
gibbs_control: GibbsControl,
|
|
39
|
+
opt_control: OptControl,
|
|
40
|
+
compute_elbo_flag: bool = False,
|
|
41
|
+
) -> Result[dict[str, Any], str]:
|
|
42
|
+
"""
|
|
43
|
+
Run Expectation-Maximization (EM) cycles to refine tumor expression programs.
|
|
44
|
+
"""
|
|
45
|
+
K_tum = eta_prior.shape[0]
|
|
46
|
+
sigma = opt_control.sigma
|
|
47
|
+
prior_num = -1.0 / (2.0 * (sigma**2))
|
|
48
|
+
|
|
49
|
+
eta_post = np.copy(eta_prior)
|
|
50
|
+
elbo_vec: list[float] = []
|
|
51
|
+
|
|
52
|
+
for em_cycle in range(1, cycle + 1):
|
|
53
|
+
# M step optimization
|
|
54
|
+
# In full workflow: E-step Gibbs sampler provides Z for tumor programs, then optimize_psi_map refines eta
|
|
55
|
+
Z_gt_tum = np.ones((eta_prior.shape[1], K_tum), dtype=np.float64) * 100.0 # Placeholder expectation
|
|
56
|
+
eta_post, opt_val = optimize_psi_map(eta_prior, Z_gt_tum, prior_num, opt_control)
|
|
57
|
+
|
|
58
|
+
if compute_elbo_flag:
|
|
59
|
+
elbo_val = float(opt_val)
|
|
60
|
+
elbo_vec.append(elbo_val)
|
|
61
|
+
|
|
62
|
+
omega = np.ones((X.shape[0], K_tum), dtype=np.float64) / K_tum
|
|
63
|
+
|
|
64
|
+
return Success(
|
|
65
|
+
{
|
|
66
|
+
"eta_prior": eta_prior,
|
|
67
|
+
"eta_post": eta_post,
|
|
68
|
+
"omega": omega,
|
|
69
|
+
"elbo": elbo_vec,
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def learn_embedding_nmf(
|
|
75
|
+
bp: BayesPrism,
|
|
76
|
+
K: int,
|
|
77
|
+
cycle: int = 50,
|
|
78
|
+
gibbs_control: Maybe[GibbsControl] = Nothing,
|
|
79
|
+
opt_control: Maybe[OptControl] = Nothing,
|
|
80
|
+
nmf_control: Maybe[NmfControl] = Nothing,
|
|
81
|
+
compute_elbo_flag: bool = False,
|
|
82
|
+
) -> Result[dict[str, Any], str]:
|
|
83
|
+
"""
|
|
84
|
+
Decompose tumor expression matrix psi_mal into K expression programs using NMF,
|
|
85
|
+
followed by Gibbs-EM refinement.
|
|
86
|
+
"""
|
|
87
|
+
if bp.reference_update == Nothing:
|
|
88
|
+
return Failure("Error: reference update missing. Please run BayesPrism first.")
|
|
89
|
+
|
|
90
|
+
ref_update = bp.reference_update.unwrap()
|
|
91
|
+
if not isinstance(ref_update, RefTumor):
|
|
92
|
+
return Failure("Error: learn_embedding requires tumor reference (RefTumor).")
|
|
93
|
+
|
|
94
|
+
psi_mal_np = (
|
|
95
|
+
ref_update.psi_mal.detach().cpu().numpy()
|
|
96
|
+
if isinstance(ref_update.psi_mal, torch.Tensor)
|
|
97
|
+
else np.asarray(ref_update.psi_mal)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
nmf_ctrl = nmf_control.value_or(NmfControl())
|
|
101
|
+
g_ctrl = gibbs_control.value_or(bp.gibbs_control)
|
|
102
|
+
o_ctrl = opt_control.value_or(bp.opt_control)
|
|
103
|
+
|
|
104
|
+
# Perform NMF decomposition
|
|
105
|
+
model = NMF(
|
|
106
|
+
n_components=K,
|
|
107
|
+
init="random",
|
|
108
|
+
random_state=nmf_ctrl.seed,
|
|
109
|
+
max_iter=nmf_ctrl.nrun,
|
|
110
|
+
)
|
|
111
|
+
W = model.fit_transform(psi_mal_np.T)
|
|
112
|
+
H = model.components_
|
|
113
|
+
nmf_eta = W.T # Shape (K, G)
|
|
114
|
+
|
|
115
|
+
# Normalize prior eta
|
|
116
|
+
nmf_eta_tensor = norm_to_one(torch.from_numpy(nmf_eta).float(), pseudo_min=ref_update.pseudo_min)
|
|
117
|
+
eta_prior = nmf_eta_tensor.numpy()
|
|
118
|
+
|
|
119
|
+
psi_env_np = (
|
|
120
|
+
ref_update.psi_env.detach().cpu().numpy()
|
|
121
|
+
if isinstance(ref_update.psi_env, torch.Tensor)
|
|
122
|
+
else np.asarray(ref_update.psi_env)
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
X_np = (
|
|
126
|
+
bp.prism.mixture.detach().cpu().numpy()
|
|
127
|
+
if isinstance(bp.prism.mixture, torch.Tensor)
|
|
128
|
+
else np.asarray(bp.prism.mixture)
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
theta_env_np = (
|
|
132
|
+
bp.posterior_theta_f.unwrap().theta.detach().cpu().numpy()
|
|
133
|
+
if bp.posterior_theta_f != Nothing
|
|
134
|
+
else bp.posterior_initial_cell_type.theta.detach().cpu().numpy()
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return run_EM(
|
|
138
|
+
eta_prior=eta_prior,
|
|
139
|
+
psi_env=psi_env_np,
|
|
140
|
+
theta_env=theta_env_np,
|
|
141
|
+
X=X_np,
|
|
142
|
+
cycle=cycle,
|
|
143
|
+
gibbs_control=g_ctrl,
|
|
144
|
+
opt_control=o_ctrl,
|
|
145
|
+
compute_elbo_flag=compute_elbo_flag,
|
|
146
|
+
)
|