Abstract
Background
Differential gene expression analysis is a prominent technique for the analysis of biomolecular data to identify genetic features associated with phenotypes. Limma—for microarray data –, and edgeR and DESeq2—for RNA-Seq data–, are the most widely used tools for differential gene expression analysis of bulk transcriptomic data.
Results
We present the differential expression features of InMoose, a Python implementation of R tools limma, edgeR, and DESeq2. We experimentally show that InMoose stands as a drop-in replacement for those tools, with nearly identical results. This ensures reproducibility when interfacing both languages in bioinformatic pipelines. InMoose is an open source software released under the GPL3 license, available at www.github.com/epigenelabs/inmoose and https://inmoose.readthedocs.io.
Conclusions
We present a new Python implementation of state-of-the-art tools limma, edgeR, and DESeq2, to perform differential gene expression analysis of bulk transcriptomic data. This new implementation exhibits results nearly identical to the original tools, improving interoperability and reproducibility between Python and R bioinformatics pipelines.
Supplementary Information
The online version contains supplementary material available at 10.1186/s12859-025-06180-7.
Keywords: Differential gene expression analysis, RNA-Seq, Microarray, Open source, Python
Background
Differential expression analysis (DEA) is a prominent technique for the analysis of high-dimensional biomolecular data that helps scientists discover genetic features associated with studied phenotypes. Despite the historical prevalence of R in bioinformatics, Python is the standard language in adjacent fields: e.g. data science, machine learning, or artificial intelligence. We have now reached a point where reference post-DEA tools may be only available in Python, such as for RNA velocity and trajectory analysis. Compatibility with Python has therefore become more crucial than ever, as this Python trend is likely to amplify in the foreseeable future. Moreover, pre-DEA steps are barely necessary in many cases, as most databases directly provide gene expression data. This opens an opportunity window for many organizations to migrate their pipelines to a single language, so that practitioners can focus on scientific challenges rather than on cross-language technicalities.
Our library InMoose [1] is an effort towards a complete Python bioinformatics ecosystem, which complements other existing initiatives (omicverse [2], scverse [3]…).
Despite those efforts, state-of-the-art DEA tools remain available in R only. To our knowledge, pydeseq2 [4] is currently the sole Python tool to offer generalized linear model-based DEA. To address this gap, we have ported into InMoose three state-of-the-art DEA tools: limma [5], edgeR [6] and DESeq2 [7]. We focus on providing drop-in replacements for the R tools, allowing practitioners to easily navigate between R and Python ecosystems while retaining reproducibility and comparability across languages.
Implementation
InMoose implements bulk transcriptomic DEA methods from three state-of-the-art tools:
Limma [5] is an R package using empirical Bayesian methods and linear models for assessing differential gene expression. Initially targeting microarray technologies, it applies to other technologies yielding data with similar statistical behavior.
edgeR [6] is an R package also based on empirical Bayesian methods and generalized linear models for the analysis of gene expression data. Its models are specifically geared towards next-generation RNA-sequencing (RNA-Seq) data.
DESeq2 [7] is another R package based on empirical Bayesian methods and generalized linear models for the analysis of gene expression data, also geared towards RNA-Seq data. In addition to DEA, DESeq2 features are widely used for data normalization.
From these three multi-purpose packages, only the features related to differential gene expression analysis have been ported to InMoose.
Rather than re-implementing the methods from scratch, we ported the R code to Python, following two goals:
Provide a drop-in replacement for R tools, with similar—if not identical—results to ensure reproducibility and avoid regressions during tool migration;
Capitalize on existing implementations: implementation details do matter, yet they are seldom described in publications or documentation. When porting code, our primary source of knowledge is the tool source code.
To illustrate this, we compare the results obtained with InMoose to those obtained with limma, edgeR and DESeq2, and with pydeseq2 [4], an alternative Python implementation of DESeq2.
Our port process was mostly performed manually. With the recent progress in generative AI, automated conversion tools claim to be able to automate similar porting activities. However, our own experience with such tools has shown their limitations. While they can greatly accelerate the conversion process, they are not exempt from errors, especially in complex mathematical manipulations. Only a careful validation process can detect and alleviate these limitations. The added value of InMoose resides precisely in our careful validation process.
Results
Experimental data and setup
We selected 12 microarray and 7 RNA-Seq datasets from GEO [8], each featuring both healthy and tumor tissue samples:
-
RNA-Seq
The experiments were run with Python 3.11.4 and R 4.2.2, with the following tool versions:
InMoose 0.7.5
Limma 3.54.2
edgeR 3.40.2
DESeq2 1.38.3
pydeseq2 0.4.11
Comparison with limma
On each microarray dataset, we computed the log2-fold-changes (LFC) between the cancer and healthy samples groups, with the InMoose limma and the limma pipelines. Figure 1A compares the LFC from both tools, showing the distribution of their absolute differences and Pearson correlation on each dataset. The results obtained by both tools are almost identical, with a Pearson correlation of 100% on all datasets (see also Fig. 2S.A), and very low LFC absolute differences—ranging below 1e-14.
Fig. 1.
Comparison of InMoose with limma, edgeR, DESeq2 and pydeseq2. A Absolute differences of log2-fold-change between limma and InMoose, and Pearson correlations. Boxes represent the median, and first and third quartiles, whiskers represent the 2.5% and 97.5% quantiles. B Absolute differences of log2-fold-change between edgeR, DESeq2, pydeseq2 and InMoose, and Pearson correlations. Boxes represent the median, and first and third quartiles, whiskers represent the 2.5% and 97.5% quantiles. C Significantly differentially expressed genes (padj < 0.05, |LFC|> 2) according to InMoose and DESeq2. Percentages averaged across the 7 RNA-Seq datasets. D Significantly differentially expressed genes (padj < 0.05, |LFC|> 2) according to InMoose and pydeseq2. Percentages averaged across the 7 RNA-Seq datasets. E Significantly differentially expressed genes (padj < 0.05, |LFC|> 2) according to DESeq2 and pydeseq2. Percentages averaged across the 7 microarray datasets
Table 1 shows the correlation between the p-values and adjusted p-values found by InMoose and limma, dataset by dataset. The correlation is perfect for all 12 microarray datasets (see also Fig. 3S.A). We also observe a very strong correlation between differentially expressed genes identified by both tools (Fig. 1S.A).
Table 1.
Pearson correlation of the p-values found by InMoose and limma
| p-values | Adjusted p-values | |
|---|---|---|
| GSE20916 | 1.000000 | 1.000000 |
| GSE23194 | 1.000000 | 1.000000 |
| GSE37364 | 1.000000 | 1.000000 |
| GSE4183 | 1.000000 | 1.000000 |
| GSE44076 | 1.000000 | 1.000000 |
| GSE62932 | 1.000000 | 1.000000 |
| GSE18520 | 1.000000 | 1.000000 |
| GSE23391 | 1.000000 | 1.000000 |
| GSE36668 | 1.000000 | 1.000000 |
| GSE38666 | 1.000000 | 1.000000 |
| GSE52037 | 1.000000 | 1.000000 |
| GSE54388 | 1.000000 | 1.000000 |
Comparison with edgeR
On each RNA-Seq dataset, we computed the log2-fold-change (LFC) between the cancer and healthy samples groups, with the InMoose edgepy LRT and the edgeR LRT pipelines. Figure 1B compares the LFC obtained from both tools, showing the distribution of their absolute differences and Pearson correlation on each dataset. The results obtained by both tools are almost identical, with a Pearson correlation of 100% on all datasets (see also Fig. 2S.B), and very low LFC absolute differences—ranging below 1e-8.
Table 2 shows the correlation between the p-values and adjusted p-values found by InMoose and edgeR, dataset by dataset. The correlation is perfect for all 7 RNA-Seq datasets (see also Fig. 3S.B).
Table 2.
Pearson correlation of the p-values found by InMoose, edgeR, DESeq2, and pydeseq
| InMoose and edgeR | InMoose and DESeq2 | InMoose and pydeseq | ||||
|---|---|---|---|---|---|---|
| p-value | Adj. p-value | p-value | Adj. p-value | p-value | Adj. p-value | |
| GSE147352 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.999566 | 0.998494 |
| GSE148389 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.999018 | 0.998783 |
| GSE174339 | 1.000000 | 1.000000 | 0.999760 | 0.999427 | 0.964969 | 0.859663 |
| GSE205512 | 1.000000 | 1.000000 | 0.995773 | 0.990636 | 0.998315 | 0.999153 |
| GSE205590 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.998418 | 0.997296 |
| GSE212991 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.996980 | 0.987426 |
| GSE254461 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.998296 | 0.996073 |
Comparison with DESeq2 and pydeseq
On each RNA-Seq dataset, we computed the log2-fold-change (LFC) between the cancer and healthy samples groups, with the InMoose deseq2, the DESeq2 and the pydeseq2 pipelines. Figure 1B compares the LFC obtained from InMoose deseq2 and DESeq2, on the one hand, and from InMoose deseq2 and pydeseq2, on the other hand. The figure shows the distribution of the LFC absolute differences and Pearson correlation on each dataset between both pairs of tools. The results obtained by InMoose deseq2 and DESeq2 are very similar, with Pearson correlations above 99% (see also Fig. 2S.C), and most LFC absolute differences below 1e-4—although larger differences occur on datasets where LFC are least correlated. Figure 1C confirms this high similarity, since InMoose and DESeq2 agree on differentially expressed genes. In contrast, the results obtained by pydeseq2 are more heterogeneous. Although the LFC correlations with InMoose are overall high (above 98% for 5 datasets out of 7, above 60% for the remaining 2), the LFC absolute differences between InMoose and pydeseq2 are significantly higher and with higher extremal values than between InMoose and DESeq2. The most striking example is GSE174339, with a Pearson correlation between the results of InMoose and pydeseq2 below 70% (see also Fig. 2S.D). Finally, the differentially expressed genes identified by pydeseq2 differ significantly from those found by InMoose and DESeq2, as shown on Fig. 1D and E, respectively.
Table 2 shows the correlation, dataset by dataset, between the p-values and adjusted p-values found by InMoose and DESeq2, on the one hand, and by InMoose and pydeseq on the other hand. The correlation between InMoose and DESeq2 is very high, if not perfect, for all 7 RNA-Seq datasets (see also Fig. 3S.C). While the correlation between InMoose and pydeseq is very high on most datasets, it is not as high as for DESeq2, and significantly drops for GSE174339.
Discussion
The porting process followed for InMoose development ensures that it replicates the algorithms of limma, edgeR and DESeq2, including the precise handling of corner edge cases.
The differences observed between InMoose and limma, edgeR and DESeq2 are due to different numerical approximations between R and Python, especially in the algorithms used to fit the GLM parameters to the input data. Note that small differences in intermediate computations may amplify, e.g. when manipulating quantiles in long-tail distributions. Such amplifications are likely responsible for the relatively larger divergence between InMoose and DESeq2. However, the very high similarity both on log-fold-changes and p-values between InMoose and limma, edgeR and DESeq2 illustrates that InMoose inherits the behaviour of those tools. This shows that InMoose can be used as a drop-in replacement for limma, edgeR and DESeq2 with very low risks of regression or divergence in the results obtained.
On the contrary, pydeseq, an independent re-implementation of DESeq2, exhibits a more divergent behaviour. While its algorithms are similar to those of DESeq2, its relatively worse ability at reproducing DESeq2 results demonstrates that implementation details do matter.
This validates the inherent advantage of our porting strategy in preserving the reliability and accuracy of well-established tools. We conclude that InMoose should be preferred when migrating DESeq2 pipelines from R to Python, to minimize the impact on results and to preserve comparability of R-based and Python-based pipelines.
Conclusion
In conclusion, InMoose is a reliable package for microarray and RNA-Seq DEA. The similarity of its results with those of limma, edgeR and DESeq2 makes it the solution of choice to ensure comparability of Python-based and R-based analyses. InMoose addresses a gap in the current Python ecosystem while minimizing the reproducibility risks between R and Python.
Availability and requirements
Project name: InMoose.
Project home page: https://github.com/epigenelabs/inmoose
Operating system: Platform independent.
Programming language: Python.
Other requirements: Numpy, Scipy.
License: GNU GPL3.
Any restrictions to use by non-academics: None.
Electronic supplementary material
Below is the link to the electronic supplementary material.
Acknowledgements
Not applicable.
Author contributions
AB and AN sponsored the work and provided guidance. MC, GA, LM, and SW have contributed to the implementation and validation of the software. MC conducted the experimental studies and prepared the manuscript. All authors reviewed the manuscript.
Funding
This work was supported by the European Union’s Horizon 2020 research and innovation program under grant agreement No 190185351.
Availability of data and materials
The datasets analyzed during the current study are available in the GEO databank: https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE20916. ttps://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE23194. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE37364. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE4183. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE44076. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE62932. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE18520. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE23391. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE36668. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE38666. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE52037. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE54388. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE147352. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE148389. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE205512. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE205590. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE174339. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE212991. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE254461.
Declarations
Ethics approval and consent to participate
Not applicable.
Consent for publication
Not applicable.
Competing interests
The authors declare no competing interests.
Footnotes
Publisher’s note
Springer Nature remains neutral with regard to jurisdictional claims in published maps and institutional affiliations.
References
- 1.Colange M, et al. Bridging the gap between R and Python in bulk transcriptomic data analysis with InMoose. Sci Rep. 2025;15:18104. [DOI] [PMC free article] [PubMed] [Google Scholar]
- 2.Zeng Z, et al. OmicVerse: a framework for bridging and deepening insights across bulk and single-cell sequencing. Nat Commun. 2024;15:5983. [DOI] [PMC free article] [PubMed] [Google Scholar]
- 3.Virshup I, et al. The scverse project provides a computational ecosystem for single-cell omics data analysis. Nat Biotechnol. 2023;41:604–6. [DOI] [PubMed] [Google Scholar]
- 4.Muzellec B, Teleńczuk M, Cabeli V, Andreux M. PyDESeq2: a python package for bulk RNA-seq differential expression analysis. Bioinformatics. 2023;39:btad547. [DOI] [PMC free article] [PubMed] [Google Scholar]
- 5.Ritchie ME, et al. Limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Res. 2015;43:e47–e47. [DOI] [PMC free article] [PubMed] [Google Scholar]
- 6.Chen Y, Lun ATL, Smyth GK. From reads to genes to pathways: differential expression analysis of RNA-Seq experiments using Rsubread and the edgeR quasi-likelihood pipeline. 2016. 10.12688/f1000research.8987.2. [DOI] [PMC free article] [PubMed]
- 7.Love MI, Huber W, Anders S. Moderated estimation of fold change and dispersion for RNA-seq data with DESeq2. Genome Biol. 2014;15:550. [DOI] [PMC free article] [PubMed] [Google Scholar]
- 8.Barrett T, et al. NCBI GEO: archive for functional genomics data sets—update. Nucleic Acids Res. 2012;41:D991–5. [DOI] [PMC free article] [PubMed] [Google Scholar]
Associated Data
This section collects any data citations, data availability statements, or supplementary materials included in this article.
Supplementary Materials
Data Availability Statement
The datasets analyzed during the current study are available in the GEO databank: https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE20916. ttps://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE23194. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE37364. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE4183. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE44076. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE62932. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE18520. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE23391. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE36668. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE38666. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE52037. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE54388. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE147352. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE148389. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE205512. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE205590. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE174339. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE212991. https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE254461.

