Python implementation of the scDblFinder workflow for doublet detection in single-cell RNA-seq data, designed to run on AnnData/Scanpy objects. This package reimplements the core algorithms of that R/Bioconductor package in Python; see the original repository for the reference implementation and further methodological background.
Given a count matrix in an AnnData object, scDblFinderPy estimates a
doublet score for each real cell and returns a final class (doublet or
singlet).
At a high level, the pipeline is:
- Optional clustering of real cells (clustered mode).
- Feature selection and artificial doublet generation.
- Combined real + artificial embedding (PCA) and KNN feature extraction.
- Iterative XGBoost training and score refinement.
- Final thresholding to obtain doublet calls.
Python 3.12 or later. The pinned dependency versions below (in
particular scanpy==1.12.1 and numpy==2.4.3) don't publish wheels for
Python 3.10 or 3.11, so pip install . will fail on those versions with a
"Could not find a version that satisfies the requirement" error. Check your
interpreter before creating the virtual environment in step 2:
python3 --version # must be 3.12+git clone <repo-url>
cd scDblFinderPypython3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pippip install .
# or, for local development (edits take effect without reinstalling):
pip install -e .This installs the exact dependency versions pinned in pyproject.toml
(numpy, pandas, scipy, anndata, scanpy, scikit-learn, xgboost,
statsmodels, leidenalg, igraph) and registers scDblFinderPy as a
normal importable package — no sys.path hacks needed. See
Reproducibility below for why the pins matter.
When use_gpu=True, clustering/PCA/neighbor search run via
rapids-singlecell (cuML/cuGraph under the hood) and XGBoost trains on the
GPU (device='cuda').
Do not try to pip install rapids-singlecell cuml into a plain venv —
cuml, cudf, and cugraph are compiled CUDA extensions that NVIDIA
distributes through conda/mamba, matched to your CUDA toolkit and driver
version. A bare pip install of these will not work on most machines. The
supported path is: build the GPU stack with conda first, then layer this
package's pure-Python dependencies on top with pip — not into the venv
from steps 2–3 above, since that would fight with conda over which
numpy/scipy/pandas build is active.
Step 1 — create the conda environment with the RAPIDS GPU stack. Use the
RAPIDS release selector to get the exact
conda create command for your CUDA toolkit/driver version and Python
3.12+, selecting at least cuml and cugraph (this also pulls in cudf
and cupy as dependencies). This package was developed and tested against:
conda create -n scdblfinder-gpu -c rapidsai -c conda-forge -c nvidia \
cuml=26.4 cugraph=26.4 python=3.12 'cuda-version>=12.0,<=13.2'
conda activate scdblfinder-gpuStep 2 — layer rapids-singlecell and this package's remaining
dependencies on top, via pip, inside that same conda environment. Use
--no-deps for this package so pip doesn't try to reinstall numpy/scipy/
pandas over the versions conda just resolved for the CUDA stack:
# rapids-singlecell ships CUDA-version-suffixed PyPI builds; match it to the
# cuda-version conda just installed (e.g. -cu12 or -cu13):
pip install rapids-singlecell-cu13 xgboost
pip install --no-deps .
# or, for local development: pip install --no-deps -e .
pip install anndata scanpy scikit-learn statsmodels leidenalg igraph(xgboost's regular PyPI wheel already includes GPU support via
device='cuda'; RAPIDS' own conda channel also ships a GPU-enabled build if
you prefer installing it alongside cuml/cugraph in step 1 instead.)
Verify the install picked up the GPU stack before running anything real:
python -c "import rapids_singlecell, cuml, cupy; print('GPU stack OK')"This was developed and tested against rapids-singlecell==0.15.0,
cuml==26.4.0, cudf==26.4.0, cugraph==26.4.0, cupy==14.0.1.
Install directly from GitHub — no local clone needed:
pip install git+https://github.com/ETHZ-INS/scDblFinderPy.gitOr, if you've already cloned it locally (see Setup), pip install . /
pip install -e . from the repo root registers the same importable
package. Either way, import it directly — no sys.path hacks required:
from scDblFinderPy.scDblFinder import compute_doublet_scorecompute_doublet_score(...) expects an AnnData object where:
adata.Xcontains raw counts (preferred), oradata.layers['counts']contains raw counts.
import scanpy as sc
from scDblFinderPy.scDblFinder import compute_doublet_score
adata = sc.read_h5ad("your_data.h5ad")
adata_out = compute_doublet_score(
adata,
clusters_col=None, # random mode — no clustering step
n_iters=3,
random_state=42,
verbose=True,
)
print(adata_out.obs[["scDblFinder_score", "scDblFinder_class"]].head())
print("Threshold:", adata_out.uns.get("scDblFinder_threshold"))adata_out = compute_doublet_score(
adata,
clusters_col="clusters", # column is computed and stored here if absent
n_iters=3,
random_state=42,
verbose=True,
)In adata.obs:
scDblFinder_score— continuous doublet score (higher = more likely doublet)scDblFinder_class— final call:doubletorsinglet
In adata.uns:
scDblFinder_threshold— the score threshold used for the final classification
If return_type='full', the returned object also includes artificial doublets.
- Multi-sample mode (R's
samples/multiSampleModearguments) is not implemented; there is nosamples_col-equivalent parameter. All cells are processed together regardless of sample of origin. - Some low-level numerical differences from the R package are expected due to library backend differences.