diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index e3c4e69db7cbd..846d863910b4c 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -547,6 +547,7 @@ Strings Interval ^^^^^^^^ +- :meth:`Index.is_monotonic_decreasing`, :meth:`Index.is_monotonic_increasing`, and :meth:`Index.is_unique` could incorrectly be ``False`` for an ``Index`` created from a slice of another ``Index``. (:issue:`57911`) - Bug in :func:`interval_range` where start and end numeric types were always cast to 64 bit (:issue:`57268`) - diff --git a/pandas/_libs/index.pyx b/pandas/_libs/index.pyx index f1be8d97c71eb..1506a76aa94a6 100644 --- a/pandas/_libs/index.pyx +++ b/pandas/_libs/index.pyx @@ -252,14 +252,24 @@ cdef class IndexEngine: return self.sizeof() cpdef _update_from_sliced(self, IndexEngine other, reverse: bool): - self.unique = other.unique - self.need_unique_check = other.need_unique_check + if other.unique: + self.unique = other.unique + self.need_unique_check = other.need_unique_check + if not other.need_monotonic_check and ( other.is_monotonic_increasing or other.is_monotonic_decreasing): - self.need_monotonic_check = other.need_monotonic_check - # reverse=True means the index has been reversed - self.monotonic_inc = other.monotonic_dec if reverse else other.monotonic_inc - self.monotonic_dec = other.monotonic_inc if reverse else other.monotonic_dec + self.need_monotonic_check = 0 + if len(self.values) > 0 and self.values[0] != self.values[-1]: + # reverse=True means the index has been reversed + if reverse: + self.monotonic_inc = other.monotonic_dec + self.monotonic_dec = other.monotonic_inc + else: + self.monotonic_inc = other.monotonic_inc + self.monotonic_dec = other.monotonic_dec + else: + self.monotonic_inc = 1 + self.monotonic_dec = 1 @property def is_unique(self) -> bool: @@ -882,14 +892,24 @@ cdef class SharedEngine: pass cpdef _update_from_sliced(self, ExtensionEngine other, reverse: bool): - self.unique = other.unique - self.need_unique_check = other.need_unique_check + if other.unique: + self.unique = other.unique + self.need_unique_check = other.need_unique_check + if not other.need_monotonic_check and ( other.is_monotonic_increasing or other.is_monotonic_decreasing): - self.need_monotonic_check = other.need_monotonic_check - # reverse=True means the index has been reversed - self.monotonic_inc = other.monotonic_dec if reverse else other.monotonic_inc - self.monotonic_dec = other.monotonic_inc if reverse else other.monotonic_dec + self.need_monotonic_check = 0 + if len(self.values) > 0 and self.values[0] != self.values[-1]: + # reverse=True means the index has been reversed + if reverse: + self.monotonic_inc = other.monotonic_dec + self.monotonic_dec = other.monotonic_inc + else: + self.monotonic_inc = other.monotonic_inc + self.monotonic_dec = other.monotonic_dec + else: + self.monotonic_inc = 1 + self.monotonic_dec = 1 @property def is_unique(self) -> bool: diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 16908fbb4fecc..8d2245d0d9978 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -961,6 +961,31 @@ def test_slice_keep_name(self): index = Index(["a", "b"], name="asdf") assert index.name == index[1:].name + def test_slice_is_unique(self): + # GH 57911 + index = Index([1, 1, 2, 3, 4]) + assert not index.is_unique + filtered_index = index[2:].copy() + assert filtered_index.is_unique + + def test_slice_is_montonic(self): + """Test that is_monotonic_decreasing is correct on slices.""" + # GH 57911 + index = Index([1, 2, 3, 3]) + assert not index.is_monotonic_decreasing + + filtered_index = index[2:].copy() + assert filtered_index.is_monotonic_decreasing + assert filtered_index.is_monotonic_increasing + + filtered_index = index[1:].copy() + assert not filtered_index.is_monotonic_decreasing + assert filtered_index.is_monotonic_increasing + + filtered_index = index[:].copy() + assert not filtered_index.is_monotonic_decreasing + assert filtered_index.is_monotonic_increasing + @pytest.mark.parametrize( "index", [