Metadata-Version: 2.4
Name: prism-de
Version: 1.0.0
Summary: PRISM: Phenotype-Resolved Inference in Single-cell Mixed models via latent disease states and contextualized differential expression
Author-email: Andrea Rubbi <ar2232@cam.ac.uk>, Ben Lengerich <blengeri@mit.edu>
License-Expression: MIT
Project-URL: Documentation, https://andrearubbi.github.io/PRISM/
Keywords: single-cell,differential expression,mixed models,EM,RNA-seq
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch>=2.2
Requires-Dist: numpy>=1.26
Requires-Dist: scipy>=1.12
Requires-Dist: pandas>=2.1
Requires-Dist: scanpy>=1.10
Requires-Dist: anndata>=0.10
Requires-Dist: matplotlib>=3.8
Requires-Dist: seaborn>=0.13
Requires-Dist: statsmodels>=0.14
Requires-Dist: scikit-learn>=1.4
Requires-Dist: pyyaml>=6.0
Requires-Dist: tqdm
Provides-Extra: wandb
Requires-Dist: wandb; extra == "wandb"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

# PRISM

**Phenotype-Resolved Inference in Single-cell Mixed models via latent disease states and contextualized differential expression**

Not every cell from a disease donor is in a disease state. PRISM is a negative-binomial mixed model for multi-donor
single-cell RNA-seq. For each cell of a disease donor it infers the posterior probability `q` that the cell is in the
disease state (cells from control donors are fixed to the healthy state). It then estimates, per gene, a constant
disease effect `alpha` and its modulation by cell-level context `z`, `theta`. Parameters are fit by EM.

## Install

```bash
pip install prism-de
```

The import name is `prism`. PRISM needs PyTorch >= 2.2. For a GPU, first install the torch build that matches your CUDA
driver ([pytorch.org](https://pytorch.org/get-started/locally/)). Fits default to `device="cuda"`, so pass
`device="cpu"` if you have no GPU.

## Quick start

```python
from prism import PRISMConfig, PRISMTrainer, generate_prism_data

data, truth = generate_prism_data(n_subjects=50, n_genes=60, n_cells_per_subject=200,
                                  rho=0.6, seed=42, device="cpu")

cfg = PRISMConfig(n_genes=data.n_genes, n_covars=data.n_covars, n_context=data.n_context,
                  ot_project_q=True, auto_q_prior=False,  # PRISM-OT, the configuration used in the paper
                  max_em_iter=30, wandb_enabled=False, device="cpu")
res = PRISMTrainer(cfg).fit(data)

print("general DE (FDR < 0.05):", int((res.q_values_de < 0.05).sum()))
print("context DE (FDR < 0.05):", int((res.q_values_context.min(dim=1).values < 0.05).sum()))
```

The fit takes about 4 minutes on a 4-core CPU. `wandb_enabled=False` turns off Weights & Biases logging, which is on
by default whenever `wandb` is installed.

## Your data

`PrismData.from_anndata` reads raw counts from `adata.X` and per-cell columns from `adata.obs`. Include an intercept
column among the covariates, and standardise continuous covariates and context variables.

```python
from prism import PrismData

adata.obs["intercept"] = 1.0
data = PrismData.from_anndata(adata, covar_cols=["intercept", "age", "sex"], context_cols=["ctx"],
                              condition_col="disease", subject_col="donor", device="cuda")
```

Then fit it with the configuration above, using `device="cuda"`.

## Outputs

| field | shape | meaning |
|---|---|---|
| `res.q_hat` | (cells,) | posterior probability that each cell is in the disease state (0 for control donors) |
| `res.rho_hat` | (disease donors,) | fraction of each disease donor's cells in the disease state |
| `res.alpha_de_hat` | (genes,) | constant disease effect (natural-log fold change) |
| `res.theta_hat` | (genes, context dims) | context modulation of the disease effect |
| `res.q_values_de` | (genes,) | BH-adjusted p-values for H0: alpha = 0 (general DE) |
| `res.q_values_context` | (genes, context dims) | BH-adjusted p-values for H0: theta = 0 (context DE) |

`res.de_summary(gene_names=...)` returns the per-gene estimates and tests as a pandas DataFrame.

## Citation

*PRISM: Phenotype-Resolved Inference in Single-Cell Mixed Models via Latent Disease States and Contextualized
Differential Expression.* NeurIPS 2026. See the [documentation](https://andrearubbi.github.io/PRISM/#citation) for the
BibTeX entry.

## License

MIT
