From f40a4910ff2814e813972de7d34514079c187785 Mon Sep 17 00:00:00 2001 From: phofl Date: Fri, 6 Nov 2020 23:14:06 +0100 Subject: [PATCH 1/3] Bug in loc raised for numeric label even when label is in Index --- doc/source/whatsnew/v1.2.0.rst | 1 + pandas/core/indexes/base.py | 9 +++++---- pandas/tests/indexing/test_loc.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 9ac3585aa9002..a8f9c4d8fb2d9 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -464,6 +464,7 @@ Indexing - Bug in indexing on a :class:`Series` or :class:`DataFrame` with a :class:`MultiIndex` with a level named "0" (:issue:`37194`) - Bug in :meth:`Series.__getitem__` when using an unsigned integer array as an indexer giving incorrect results or segfaulting instead of raising ``KeyError`` (:issue:`37218`) - Bug in :meth:`Index.where` incorrectly casting numeric values to strings (:issue:`37591`) +- Bug in :meth:`Series.loc` and :meth:`DataFrame.loc` raises when numeric label was given for object :class:`Index` although label was in :class:`Index` (:issue:`26491`) Missing ^^^^^^^ diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 98ec3b55e65d9..26bcaa7c53383 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -5200,13 +5200,14 @@ def _maybe_cast_slice_bound(self, label, side: str_t, kind): # We are a plain index here (sub-class override this method if they # wish to have special treatment for floats/ints, e.g. Float64Index and # datetimelike Indexes - # reject them - if is_float(label): + # reject them, if index does not contain label + if is_float(label) and label not in self.values: self._invalid_indexer("slice", label) # we are trying to find integer bounds on a non-integer based index - # this is rejected (generally .loc gets you here) - elif is_integer(label): + # this is rejected (generally .loc gets you here) if label is not in + # index + elif is_integer(label) and label not in self.values: self._invalid_indexer("slice", label) return label diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index c1a5db992d3df..226b6083216a4 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -1579,3 +1579,13 @@ def test_loc_setitem_dt64tz_values(self): s2["a"] = expected result = s2["a"] assert result == expected + + +@pytest.mark.parametrize("klass", [DataFrame, Series]) +@pytest.mark.parametrize("value", [1, 1.5]) +def test_loc_int_in_object_index(klass, value): + # GH: 26491 + obj = klass(range(4), index=[value, "first", 2, "third"]) + result = obj.loc[value:"third"] + expected = klass(range(4), index=[value, "first", 2, "third"]) + tm.assert_equal(result, expected) From 7ecd86ccc5f68bf0ec7569ae5298bbdf619a6d8b Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 8 Nov 2020 01:32:58 +0100 Subject: [PATCH 2/3] Simplify if else conditions --- pandas/core/indexes/base.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 26bcaa7c53383..6d06e52c39941 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -5201,13 +5201,7 @@ def _maybe_cast_slice_bound(self, label, side: str_t, kind): # wish to have special treatment for floats/ints, e.g. Float64Index and # datetimelike Indexes # reject them, if index does not contain label - if is_float(label) and label not in self.values: - self._invalid_indexer("slice", label) - - # we are trying to find integer bounds on a non-integer based index - # this is rejected (generally .loc gets you here) if label is not in - # index - elif is_integer(label) and label not in self.values: + if (is_float(label) or is_integer(label)) and label not in self.values: self._invalid_indexer("slice", label) return label From 94b4f985b83058b9ecac0f096de72e391fef0331 Mon Sep 17 00:00:00 2001 From: phofl Date: Sun, 8 Nov 2020 22:46:12 +0100 Subject: [PATCH 3/3] Use frame_or_series fixture --- pandas/tests/indexing/test_loc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index 226b6083216a4..3d45ebd4635d2 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -1581,11 +1581,10 @@ def test_loc_setitem_dt64tz_values(self): assert result == expected -@pytest.mark.parametrize("klass", [DataFrame, Series]) @pytest.mark.parametrize("value", [1, 1.5]) -def test_loc_int_in_object_index(klass, value): +def test_loc_int_in_object_index(frame_or_series, value): # GH: 26491 - obj = klass(range(4), index=[value, "first", 2, "third"]) + obj = frame_or_series(range(4), index=[value, "first", 2, "third"]) result = obj.loc[value:"third"] - expected = klass(range(4), index=[value, "first", 2, "third"]) + expected = frame_or_series(range(4), index=[value, "first", 2, "third"]) tm.assert_equal(result, expected)