From 52d8e3b033675084ea5cce5a8eb95c0b0698b377 Mon Sep 17 00:00:00 2001 From: jschendel Date: Thu, 3 May 2018 18:12:02 -0600 Subject: [PATCH 1/2] BUG: Fix IntervalIndex.get_loc/get_indexer for IntervalIndex of length one --- doc/source/whatsnew/v0.23.0.txt | 1 + pandas/core/indexes/interval.py | 5 ++++- pandas/tests/indexes/interval/test_interval.py | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index 4ad40fe0f7f2b..ce350ae6944d8 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -1245,6 +1245,7 @@ Indexing - Bug in ``Series.is_unique`` where extraneous output in stderr is shown if Series contains objects with ``__ne__`` defined (:issue:`20661`) - Bug in ``.loc`` assignment with a single-element list-like incorrectly assigns as a list (:issue:`19474`) - Bug in partial string indexing on a ``Series/DataFrame`` with a monotonic decreasing ``DatetimeIndex`` (:issue:`19362`) +- Bug in ``IntervalIndex.get_loc()`` and ``IntervalIndex.get_indexer()`` when used with an :class:`IntervalIndex` containing a single interval (:issue:`17284`, :issue:`20921`) MultiIndex ^^^^^^^^^^ diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 54800d0d76d2e..91a47ff74f394 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -938,8 +938,11 @@ def _searchsorted_monotonic(self, label, side, exclude_label=False): if isinstance(label, IntervalMixin): raise NotImplementedError + # GH 20921: "not is_monotonic_increasing" for the second condition + # instead of "is_monotonic_decreasing" to account for single element + # indexes being both increasing and decreasing if ((side == 'left' and self.left.is_monotonic_increasing) or - (side == 'right' and self.left.is_monotonic_decreasing)): + (side == 'right' and not self.left.is_monotonic_increasing)): sub_idx = self.right if self.open_right or exclude_label: label = _get_next_label(label) diff --git a/pandas/tests/indexes/interval/test_interval.py b/pandas/tests/indexes/interval/test_interval.py index 71a6f78125004..9920809a18a24 100644 --- a/pandas/tests/indexes/interval/test_interval.py +++ b/pandas/tests/indexes/interval/test_interval.py @@ -497,6 +497,14 @@ def test_get_loc_interval(self): pytest.raises(KeyError, self.index.get_loc, Interval(-1, 0, 'left')) + # Make consistent with test_interval_new.py (see #16316, #16386) + @pytest.mark.parametrize('item', [3, Interval(1, 4)]) + def test_get_loc_length_one(self, item, closed): + # GH 20921 + index = IntervalIndex.from_tuples([(0, 5)], closed=closed) + result = index.get_loc(item) + assert result == 0 + # To be removed, replaced by test_interval_new.py (see #16316, #16386) def test_get_indexer(self): actual = self.index.get_indexer([-1, 0, 0.5, 1, 1.5, 2, 3]) @@ -544,6 +552,16 @@ def test_get_indexer_subintervals(self): expected = np.array([0, 0, 0], dtype='intp') tm.assert_numpy_array_equal(actual, expected) + # Make consistent with test_interval_new.py (see #16316, #16386) + @pytest.mark.parametrize('item', [ + [3], np.arange(1, 5), [Interval(1, 4)], interval_range(1, 4)]) + def test_get_indexer_length_one(self, item, closed): + # GH 17284 + index = IntervalIndex.from_tuples([(0, 5)], closed=closed) + result = index.get_indexer(item) + expected = np.array([0] * len(item), dtype='intp') + tm.assert_numpy_array_equal(result, expected) + # To be removed, replaced by test_interval_new.py (see #16316, #16386) def test_contains(self): # Only endpoints are valid. From 3c82ef3791cebe6576433b65f2e3067ef29fde12 Mon Sep 17 00:00:00 2001 From: jschendel Date: Fri, 4 May 2018 12:55:10 -0600 Subject: [PATCH 2/2] add to api.rst --- doc/source/api.rst | 2 ++ doc/source/whatsnew/v0.23.0.txt | 2 +- pandas/core/indexes/interval.py | 14 ++++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 93edd090d846b..d00e5511f1100 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1632,6 +1632,8 @@ IntervalIndex Components IntervalIndex.length IntervalIndex.values IntervalIndex.is_non_overlapping_monotonic + IntervalIndex.get_loc + IntervalIndex.get_indexer .. _api.multiindex: diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index ce350ae6944d8..09ca4f403399b 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -1245,7 +1245,7 @@ Indexing - Bug in ``Series.is_unique`` where extraneous output in stderr is shown if Series contains objects with ``__ne__`` defined (:issue:`20661`) - Bug in ``.loc`` assignment with a single-element list-like incorrectly assigns as a list (:issue:`19474`) - Bug in partial string indexing on a ``Series/DataFrame`` with a monotonic decreasing ``DatetimeIndex`` (:issue:`19362`) -- Bug in ``IntervalIndex.get_loc()`` and ``IntervalIndex.get_indexer()`` when used with an :class:`IntervalIndex` containing a single interval (:issue:`17284`, :issue:`20921`) +- Bug in :meth:`IntervalIndex.get_loc` and :meth:`IntervalIndex.get_indexer` when used with an :class:`IntervalIndex` containing a single interval (:issue:`17284`, :issue:`20921`) MultiIndex ^^^^^^^^^^ diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 91a47ff74f394..766ac7b14120e 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -159,20 +159,22 @@ class IntervalIndex(IntervalMixin, Index): Attributes ---------- - left - right closed - mid + is_non_overlapping_monotonic + left length + mid + right values - is_non_overlapping_monotonic Methods ------- + contains from_arrays - from_tuples from_breaks - contains + from_tuples + get_indexer + get_loc Examples ---------