Skip to main content
v2026.11,858 entries · CC-BY 4.0
LAC HealthMedical & Research SuppliesReagents, PPE & instruments — chain-of-custody documented.Fast, traceable sourcing built for regulated research environments, from bench consumables to instrumentation.Shop lac.us CodeCASRAIlac.us

PyDESeq2: Install and Run Differential Expression in Python

Install PyDESeq2, run a bulk RNA-seq differential expression analysis in Python, and map R DESeq2 names to their PyDESeq2 equivalents.

Written and maintained by CASRAI Editorial Board

Last updated

PyDESeq2 is a Python reimplementation of DESeq2, written from scratch, for differential expression analysis of bulk RNA-seq count data. If you have a raw count table and sample metadata and want to test which genes differ between conditions without leaving Python, this guide gives the install routes, a minimal runnable pipeline, the input shape that trips most first runs, and a cross-walk from R DESeq2 names to their PyDESeq2 equivalents. It was read against the official documentation and repository on 2026-11-07.

What PyDESeq2 is used for in research

PyDESeq2 tests for differential expression in bulk RNA-seq. Its documentation describes it as a Python implementation of the DESeq2 method, built on the AnnData data structure and part of the scverse ecosystem. It supports single-factor and multi-factor designs, categorical or continuous factors, Wald tests, and optional apeGLM log fold change shrinkage. The defaults are designed to broadly match DESeq2 v1.34.0, although the documentation cautions that some values and features may differ from R DESeq2. It is released under the MIT licence and is free to use.

The method is described in Muzellec, Telenczuk, Cabeli and Andreux, “PyDESeq2: a python package for bulk RNA-seq differential expression analysis”, Bioinformatics 2023, doi:10.1093/bioinformatics/btad547 (first posted as a bioRxiv preprint in December 2022). Cite it if you report results from the package. For the R-side methods landscape, see DESeq2 vs edgeR and the broader RNA-seq experimental design and analysis guide.

Install PyDESeq2 (pip, conda, uv, bioconda)

All routes below come from the official installation page and the project README.

Route Command Where it is documented
pip pip install pydeseq2 Documentation installation page
conda environment, then pip conda env create -n pydeseq2, then conda activate pydeseq2, then pip install pydeseq2 Documentation installation page
uv uv add pydeseq2 GitHub README
bioconda conda install -c bioconda pydeseq2 GitHub README

The repository states that continuous integration tests Python 3.12 to 3.14. The installation page states no minimum Python version. If you are setting up a fresh environment, installing Anaconda for Python covers the conda side.

Step-by-step: run a differential expression analysis

The steps below follow the official minimal pipeline example (using the package’s synthetic example data).

  1. Prepare the counts. A pandas DataFrame of raw, non-negative integer counts with samples as rows and genes as columns.
  2. Prepare the metadata. A DataFrame with one row per sample; its index must match the counts index. It must contain the column you name in the design (here condition).
  3. Import the classes.
    from pydeseq2.datasets import load_example_data
    from pydeseq2.dds import DeseqDataSet
    from pydeseq2.default_inference import DefaultInference
    from pydeseq2.ds import DeseqStats
  4. Load data (the example loader; replace with your own DataFrames).
    counts_df = load_example_data(modality="raw_counts", dataset="synthetic", debug=False)
    metadata = load_example_data(modality="metadata", dataset="synthetic", debug=False)
  5. Fit the model.
    inference = DefaultInference(n_cpus=8)
    dds = DeseqDataSet(counts=counts_df, metadata=metadata, design="~condition", refit_cooks=True, inference=inference)
    dds.deseq2()
  6. Test a contrast.
    ds = DeseqStats(dds, contrast=["condition", "B", "A"], inference=inference)
    ds.summary()
    results = ds.results_df

The contrast is given as the factor name followed by the two levels to compare, here condition B against condition A. n_cpus sets the number of CPU cores used for inference; adjust it to your machine.

Output and how to read it

ds.results_df is a DataFrame with one row per gene and the columns baseMean, log2FoldChange, lfcSE, stat, pvalue and padj. The PyDESeq2 example page does not define these columns; the meanings below are the standard DESeq2 convention that the package follows.

  • baseMean: mean of normalised counts across samples.
  • log2FoldChange: the estimated log2 fold change for the contrast you requested.
  • lfcSE: standard error of that estimate.
  • stat: the Wald test statistic.
  • pvalue: the unadjusted p-value.
  • padj: the p-value adjusted for multiple testing across genes. In DESeq2 and edgeR this is a Benjamini-Hochberg adjusted value, and papers usually filter on it at a 5% or 10% false discovery rate.

Filter on padj, not pvalue, when listing differentially expressed genes. To visualise the table, see volcano plots for RNA-seq.

R DESeq2 to PyDESeq2 cross-walk

R DESeq2 concept PyDESeq2 equivalent
DESeqDataSet object DeseqDataSet (pydeseq2.dds)
DESeq() fitting call dds.deseq2()
results() with a contrast DeseqStats(dds, contrast=[...]), then ds.summary() and ds.results_df
Count matrix, genes as rows pandas DataFrame, samples as rows and genes as columns

This is a map of names, not a guarantee of identical numbers: the documentation states that defaults broadly match DESeq2 v1.34.0 and that some values may differ.

Troubleshooting

Counts and metadata do not line up

The counts DataFrame has samples as rows and genes as columns, which is the opposite orientation to the genes-by-samples count matrix R users are used to. If your table is genes by samples, transpose it first. The metadata index must match the sample index of the counts.

Non-integer or negative values

The input must be raw, non-negative integer counts, not normalised values. Supply the counts from your quantification step rather than TPM or already-normalised tables. See creating a DataFrame in Python if you are building the tables by hand.

Installation problems

Use a clean conda environment as in the table above, and install with pip inside it. If you are on a bioconda-based setup, use the bioconda command instead.

Free alternatives

Tool Language and home Licence Install
PyDESeq2 Python, scverse MIT pip install pydeseq2
DESeq2 R, Bioconductor: negative binomial model for count data LGPL (>= 3) BiocManager::install("DESeq2")
edgeR R, Bioconductor: differential expression of sequence count data GPL (>= 2) BiocManager::install("edgeR")

Licences and install commands are from each project’s own page, read 2026-11-07. For a method-level comparison of the two R packages, see DESeq2 vs edgeR; for other free tools, see free statistical software.

FAQ

What is PyDESeq2?

A Python implementation of the DESeq2 method for bulk RNA-seq differential expression, built on AnnData and part of scverse, released under the MIT licence.

How do I install PyDESeq2?

Run pip install pydeseq2. Conda users can run conda install -c bioconda pydeseq2, and uv users uv add pydeseq2.

Does PyDESeq2 give the same results as DESeq2?

Its defaults are designed to broadly match DESeq2 v1.34.0, but the documentation states that some values or features may differ from R DESeq2.

What input does PyDESeq2 need?

Raw non-negative integer counts in a samples-by-genes pandas DataFrame, plus a metadata DataFrame whose index matches the samples.

How do I cite PyDESeq2?

Cite Muzellec, Telenczuk, Cabeli and Andreux, Bioinformatics 2023, doi:10.1093/bioinformatics/btad547.

Sources

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about PyDESeq2: Install and Run Differential Expression in Python

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →