Metadata-Version: 2.4
Name: decontx-scanpy
Version: 0.1.0
Summary: Scanpy-native port of DecontX (Yang et al. 2020) — ambient RNA decontamination for droplet scRNA-seq, validated to machine precision against the upstream Bioconductor kernels.
Author-email: chansigit <chansigit@gmail.com>
License: MIT
Project-URL: Upstream R package, https://github.com/campbio/decontX
Project-URL: DecontX paper, https://doi.org/10.1186/s13059-020-1950-6
Keywords: DecontX,ambient-RNA,decontamination,single-cell,scRNA-seq,scanpy,anndata,bioinformatics,variational-EM
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.23
Requires-Dist: scipy>=1.10
Provides-Extra: anndata
Requires-Dist: anndata>=0.8; extra == "anndata"
Requires-Dist: pandas>=1.5; extra == "anndata"
Provides-Extra: clustering
Requires-Dist: scanpy>=1.9; extra == "clustering"
Requires-Dist: scikit-learn>=1.1; extra == "clustering"
Requires-Dist: anndata>=0.8; extra == "clustering"
Requires-Dist: pandas>=1.5; extra == "clustering"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: anndata>=0.8; extra == "dev"
Requires-Dist: pandas>=1.5; extra == "dev"
Dynamic: license-file

# decontx-scanpy

Scanpy-native Python port of **DecontX** (Yang et al., *Genome Biology* 2020;
Bioconductor package [campbio/decontX](https://github.com/campbio/decontX)) —
estimation and removal of ambient RNA contamination in droplet-based
single-cell RNA-seq data. Import name: `pydecontx`.

- **Faithful**: the variational-EM kernels are a line-for-line vectorized port
  of the upstream `src/DecontX.cpp`, validated against the *actual* upstream
  kernels (compiled from source and driven by the original R EM loop) to
  **machine precision** — max θ difference ~4e-16 with a shared
  initialization; Pearson r > 0.99 end-to-end with independent RNGs.
- **Complete**: automatic broad-cluster estimation (PCA → UMAP → DBSCAN with
  k-means fallback, as in R), empty-droplet `background` support incl.
  per-batch backgrounds and barcode-overlap checks, multi-batch mode,
  in-place AnnData results following scanpy conventions.
- **Fast, no compiler**: pure numpy/scipy; nonzeros are grouped by cluster
  once so each EM pass streams cache-resident columns (~0.5 s/iteration at
  20k cells × 12k genes × 22M nonzeros, single core).
- **No R required.** Only DecontX is ported (not DecontPro).

## Install

```bash
pip install decontx-scanpy                # core (numpy + scipy)
pip install "decontx-scanpy[clustering]"  # + scanpy/sklearn for auto-clustering
```

## Usage

```python
import scanpy as sc
from pydecontx import decontx

adata = sc.read_h5ad("filtered_cells.h5ad")   # raw counts, cells x genes

# recommended: use your own annotation / clustering
decontx(adata, z="cell_type", batch="sample")           # modifies in place

# or let DecontX estimate broad clusters (requires [clustering] extra)
decontx(adata)

# with empty droplets as the ambient profile
decontx(adata, background=raw_droplets_adata)

adata.layers["decontX_counts"]        # decontaminated counts (non-integer; round if needed)
adata.obs["decontX_contamination"]    # per-cell contamination fraction
adata.obs["decontX_clusters"]         # clusters used
adata.uns["decontX"]["estimates"]     # theta/phi/eta/delta/log-likelihood per batch
```

A plain `cells × genes` matrix (numpy or scipy sparse) is also accepted; a
result dict is then returned, mirroring the R `list` return. A
`simulate_contamination()` generator (port of the R one) is included for
testing.

Key parameters (same semantics as R): `delta=(10, 10)` with
`estimate_delta=True` controls the prior on per-cell contamination — set
`estimate_delta=False` with a larger second value for more aggressive
removal; `max_iter=500`, `convergence=0.001`.

## The model

Each cell's observed counts are a two-component multinomial mixture: a
*native* gene distribution `phi[:, k]` of the cell's population *k*, and a
*contamination* distribution `eta[:, k]` aggregating every **other**
population's expression, mixed by a per-cell native proportion
`theta ~ Beta(delta)`. Variational EM yields per-transcript native
probabilities; the decontaminated matrix is `counts × P(native)`.

## Validation

The test suite (`tests/`, 30 tests) has three layers:

1. **R parity**: the upstream `DecontX.cpp` is compiled via
   `Rcpp::sourceCpp` and driven by a verbatim copy of the R EM loop on
   identical inputs. With a shared initial θ and fixed δ the Python kernels
   match to ~4e-16 (θ), ~5e-13 (decontaminated matrix); with δ re-estimated,
   ~2e-4; end-to-end r > 0.99. Cached reference outputs ship in the sdist,
   so `pytest` needs no R installation.
2. **Kernel units**: EM step vs a literal dense transcription of the C++
   loops; Dirichlet-MLE (Minka fixed point) recovery.
3. **Functional**: ground-truth recovery on simulations (r = 0.998,
   MAE 0.004 at ~10% contamination), ~99% removal of marker-gene
   cross-contamination, background / batch / error paths.

## Citation

If you use this package, please cite the DecontX paper:

> Yang, S., Corbett, S.E., Koga, Y. et al. Decontamination of ambient RNA in
> single-cell RNA-seq with DecontX. *Genome Biology* 21, 57 (2020).

## License

MIT. Ported from the MIT-licensed Bioconductor package
[decontX](https://github.com/campbio/decontX); see LICENSE for attribution.
