Repository: owkin/PyDESeq2
Pull request #30 (2023-01-02 09:34:31)

Index sorting
This PR fixes an issue that appears when the count matrix and the clinical data provided to a `DeseqDataSet` have identical sets of samples, but in a different order, by sorting the indices at initialization.


Patch:
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 87dd959..b5ecb2e 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -3,8 +3,8 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-Welcome to PyDESeq2's documentation!
-====================================
+PyDESeq2 documentation
+======================
 
 This package is a python implementation of the `DESeq2 <https://bioconductor.org/packages/release/bioc/html/DESeq2.html>`_ method [1]_
 for differential expression analysis (DEA) with bulk RNA-seq data, originally in R.
@@ -15,73 +15,33 @@ As PyDESeq2 is a re-implementation of `DESeq2 <https://bioconductor.org/packages
 Currently, available features broadly correspond to the default settings of DESeq2 (v1.34.0) for single-factor analysis, with an optional `apeGLM <https://academic.oup.com/bioinformatics/article/35/12/2084/5159452>`_ LFC shrinkage [2]_.
 We plan to implement more in the near future. In case there is a feature you would particularly like to be implemented, feel free to open an issue on GitHub.
 
+
 .. toctree::
    :maxdepth: 2
-   :caption: Contents:
- 
-   api/index
-
-Installation
-------------
-
-`PyDESeq2` can be installed from PyPI:
-
-.. code-block:: bash 
-   
-   pip install pydeseq2
-
-We recommend installing within a conda environment:
-
-.. code-block:: python
-
-   conda env create -n pydeseq2
-   conda activate pydeseq2
-   pip install pydeseq2
-
-
-If you're interested in contributing or want access to the development version, please see the :ref:`contributing`.
+   :caption: Usage:
 
-Requirements
-------------
+   usage/installation
+   usage/requirements
+   usage/getting_started
+   usage/contributing
 
-The list of package version requirements is available in  ``setup.py``, and will be automatically installed along PyDESeq2 when using PyPI.
-For reference, the code was tested with python 3.8 and the following package versions:
+.. toctree::
+   :maxdepth: 2
+   :caption: Contents:
 
-- numpy 1.23.0
-- pandas 1.4.3
-- scikit-learn 1.1.1
-- scipy 1.8.1
-- statsmodels 0.13.2
+   api/index
 
-Please don't hesitate to open an issue in case you encounter any issue due to possible deprecations.
 
 Documentation
 -------------
 
 The documentation is automatically build using `Sphinx <https://www.sphinx-doc.org/en/master/>`_, and hosted `here on ReadTheDoc <https://pydeseq2.readthedocs.io/en/latest/>`_.
 
-Getting started
----------------
-
-The `notebooks directory <https://github.com/owkin/PyDESeq2/blob/main/notebooks/README.md>`_ contains minimal examples on how to use PyDESeq2, in the form of jupyter notebooks.
-
-You can also try them from your browser (on synthetic data only): |Binder|
-
-.. |Binder| image:: https://mybinder.org/badge_logo.svg 
-   :target: https://mybinder.org/v2/gh/owkin/PyDESeq2/HEAD?labpath=notebooks%2Findex.ipynb
-
-.. _contributing:
-
-Contributing
-------------
-
-PyDESeq2 is a living project and any contributions are welcome! The project is hosted on `Github <https://github.com/owkin/PyDESeq2>`_.
-Feel free to come and open new PRs or issues.
 
 Citing this work
 ----------------
 
-::  
+::
 
    @article{muzellec2022pydeseq2,
    title={PyDESeq2: a python package for bulk RNA-seq differential expression analysis},
diff --git a/docs/source/usage/contributing.rst b/docs/source/usage/contributing.rst
new file mode 100644
index 0000000..2a8451d
--- /dev/null
+++ b/docs/source/usage/contributing.rst
@@ -0,0 +1,5 @@
+Contributing
+------------
+
+PyDESeq2 is a living project and any contributions are welcome! The project is hosted on `Github <https://github.com/owkin/PyDESeq2>`_.
+Feel free to come and open new PRs or issues.
\ No newline at end of file
diff --git a/docs/source/usage/getting_started.rst b/docs/source/usage/getting_started.rst
new file mode 100644
index 0000000..c42c74a
--- /dev/null
+++ b/docs/source/usage/getting_started.rst
@@ -0,0 +1,11 @@
+Getting started
+---------------
+
+The `notebooks directory <https://github.com/owkin/PyDESeq2/blob/main/notebooks/README.md>`_ contains minimal examples on how to use PyDESeq2, in the form of jupyter notebooks.
+
+You can also try them from your browser (on synthetic data only): |Binder|
+
+.. |Binder| image:: https://mybinder.org/badge_logo.svg 
+   :target: https://mybinder.org/v2/gh/owkin/PyDESeq2/HEAD?labpath=notebooks%2Findex.ipynb
+
+.. _contributing:
\ No newline at end of file
diff --git a/docs/source/usage/installation.rst b/docs/source/usage/installation.rst
new file mode 100644
index 0000000..caa125b
--- /dev/null
+++ b/docs/source/usage/installation.rst
@@ -0,0 +1,20 @@
+Installation
+------------
+
+`PyDESeq2` can be installed from PyPI:
+
+.. code-block:: bash
+
+   pip install pydeseq2
+
+We recommend installing within a conda environment:
+
+.. code-block:: python
+
+   conda env create -n pydeseq2
+   conda activate pydeseq2
+   pip install pydeseq2
+
+
+If you're interested in contributing or want access to the development version,
+please see the :doc:`contributing` section.
diff --git a/docs/source/usage/requirements.rst b/docs/source/usage/requirements.rst
new file mode 100644
index 0000000..68a759b
--- /dev/null
+++ b/docs/source/usage/requirements.rst
@@ -0,0 +1,13 @@
+Requirements
+------------
+
+The list of package version requirements is available in  ``setup.py``, and will be automatically installed along PyDESeq2 when using PyPI.
+For reference, the code was tested with python 3.8 and the following package versions:
+
+- numpy 1.23.0
+- pandas 1.4.3
+- scikit-learn 1.1.1
+- scipy 1.8.1
+- statsmodels 0.13.2
+
+Please don't hesitate to open an issue in case you encounter any problems due to possible deprecations.
\ No newline at end of file
diff --git a/pydeseq2/DeseqDataSet.py b/pydeseq2/DeseqDataSet.py
index 17bf63f..76676ad 100644
--- a/pydeseq2/DeseqDataSet.py
+++ b/pydeseq2/DeseqDataSet.py
@@ -175,12 +175,14 @@ class DeseqDataSet:
         test_valid_counts(counts)
         self.counts = counts
 
-        # Import clinical data and convert design_column to string
-        self.clinical = clinical
-        if not self.counts.index.identical(self.clinical.index):
-            raise ValueError(
-                "The count matrix and clinical data should have the same index."
+        if set(self.counts.index) != set(clinical.index):
+            raise KeyError(
+                "The count matrix and clinical data "
+                "should contain the same sample indexes."
             )
+
+        # Import clinical data and convert design_column to string
+        self.clinical = clinical.loc[self.counts.index]
         self.design_factor = design_factor
         if self.clinical[self.design_factor].isna().any():
             raise ValueError("NaNs are not allowed in the design factor.")


Test patch:
diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py
index febbb29..42a5a6c 100644
--- a/tests/test_edge_cases.py
+++ b/tests/test_edge_cases.py
@@ -141,7 +141,7 @@ def test_indexes():
     )
     clinical_df = pd.DataFrame({"condition": [0, 1]}, index=["sample01", "sample02"])
 
-    with pytest.raises(ValueError):
+    with pytest.raises(KeyError):
         DeseqDataSet(
             counts_df,
             clinical_df,