From a2e6ddc6de6f5ab708d86c0caf5227c9f5888fb9 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Mon, 13 May 2024 07:58:59 -1000 Subject: [PATCH] CLN: int slice on Index[float] as positional (#58646) --- doc/source/whatsnew/v0.13.0.rst | 1 - doc/source/whatsnew/v3.0.0.rst | 1 + pandas/core/indexes/base.py | 19 ------------------- pandas/tests/frame/indexing/test_indexing.py | 14 ++++++++------ pandas/tests/indexing/test_floats.py | 16 ++-------------- 5 files changed, 11 insertions(+), 40 deletions(-) diff --git a/doc/source/whatsnew/v0.13.0.rst b/doc/source/whatsnew/v0.13.0.rst index a624e81d17db9..3c5488a47bdf2 100644 --- a/doc/source/whatsnew/v0.13.0.rst +++ b/doc/source/whatsnew/v0.13.0.rst @@ -345,7 +345,6 @@ Float64Index API change .. ipython:: python :okwarning: - s[2:4] s.loc[2:4] s.iloc[2:4] diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index 08b3175ad0ad6..083e004fb94fa 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -225,6 +225,7 @@ Removal of prior version deprecations/changes - All arguments except ``name`` in :meth:`Index.rename` are now keyword only (:issue:`56493`) - All arguments except the first ``path``-like argument in IO writers are now keyword only (:issue:`54229`) - Changed behavior of :meth:`Series.__getitem__` and :meth:`Series.__setitem__` to always treat integer keys as labels, never as positional, consistent with :class:`DataFrame` behavior (:issue:`50617`) +- Changed behavior of :meth:`Series.__getitem__`, :meth:`Series.__setitem__`, :meth:`DataFrame.__getitem__`, :meth:`DataFrame.__setitem__` with an integer slice on objects with a floating-dtype index. This is now treated as *positional* indexing (:issue:`49612`) - Disallow a callable argument to :meth:`Series.iloc` to return a ``tuple`` (:issue:`53769`) - Disallow allowing logical operations (``||``, ``&``, ``^``) between pandas objects and dtype-less sequences (e.g. ``list``, ``tuple``); wrap the objects in :class:`Series`, :class:`Index`, or ``np.array`` first instead (:issue:`52264`) - Disallow automatic casting to object in :class:`Series` logical operations (``&``, ``^``, ``||``) between series with mismatched indexes and dtypes other than ``object`` or ``bool`` (:issue:`52538`) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index d6849136bb487..308205678e388 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4005,25 +4005,6 @@ def _convert_slice_indexer(self, key: slice, kind: Literal["loc", "getitem"]): # TODO(GH#50617): once Series.__[gs]etitem__ is removed we should be able # to simplify this. - if lib.is_np_dtype(self.dtype, "f"): - # We always treat __getitem__ slicing as label-based - # translate to locations - if kind == "getitem" and is_index_slice and not start == stop and step != 0: - # exclude step=0 from the warning because it will raise anyway - # start/stop both None e.g. [:] or [::-1] won't change. - # exclude start==stop since it will be empty either way, or - # will be [:] or [::-1] which won't change - warnings.warn( - # GH#49612 - "The behavior of obj[i:j] with a float-dtype index is " - "deprecated. In a future version, this will be treated as " - "positional instead of label-based. For label-based slicing, " - "use obj.loc[i:j] instead", - FutureWarning, - stacklevel=find_stack_level(), - ) - return self.slice_indexer(start, stop, step) - if kind == "getitem": # called from the getitem slicers, validate that we are in fact integers if is_index_slice: diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py index bc233c5b86b4b..9cd2c2515f49a 100644 --- a/pandas/tests/frame/indexing/test_indexing.py +++ b/pandas/tests/frame/indexing/test_indexing.py @@ -724,6 +724,14 @@ def test_getitem_setitem_boolean_multi(self): expected.loc[[0, 2], [1]] = 5 tm.assert_frame_equal(df, expected) + def test_getitem_float_label_positional(self): + # GH 53338 + index = Index([1.5, 2]) + df = DataFrame(range(2), index=index) + result = df[1:2] + expected = DataFrame([1], index=[2.0]) + tm.assert_frame_equal(result, expected) + def test_getitem_setitem_float_labels(self): index = Index([1.5, 2, 3, 4, 5]) df = DataFrame(np.random.default_rng(2).standard_normal((5, 5)), index=index) @@ -748,12 +756,6 @@ def test_getitem_setitem_float_labels(self): expected = df.iloc[0:2] tm.assert_frame_equal(result, expected) - expected = df.iloc[0:2] - msg = r"The behavior of obj\[i:j\] with a float-dtype index" - with tm.assert_produces_warning(FutureWarning, match=msg): - result = df[1:2] - tm.assert_frame_equal(result, expected) - # #2727 index = Index([1.0, 2.5, 3.5, 4.5, 5.0]) df = DataFrame(np.random.default_rng(2).standard_normal((5, 5)), index=index) diff --git a/pandas/tests/indexing/test_floats.py b/pandas/tests/indexing/test_floats.py index 8597ee1198ff0..f9b9e8a6c7c28 100644 --- a/pandas/tests/indexing/test_floats.py +++ b/pandas/tests/indexing/test_floats.py @@ -488,24 +488,12 @@ def test_floating_misc(self, indexer_sl): for fancy_idx in [[5, 0], np.array([5, 0])]: tm.assert_series_equal(indexer_sl(s)[fancy_idx], expected) - warn = FutureWarning if indexer_sl is tm.setitem else None - msg = r"The behavior of obj\[i:j\] with a float-dtype index" - # all should return the same as we are slicing 'the same' - with tm.assert_produces_warning(warn, match=msg): - result1 = indexer_sl(s)[2:5] result2 = indexer_sl(s)[2.0:5.0] result3 = indexer_sl(s)[2.0:5] result4 = indexer_sl(s)[2.1:5] - tm.assert_series_equal(result1, result2) - tm.assert_series_equal(result1, result3) - tm.assert_series_equal(result1, result4) - - expected = Series([1, 2], index=[2.5, 5.0]) - with tm.assert_produces_warning(warn, match=msg): - result = indexer_sl(s)[2:5] - - tm.assert_series_equal(result, expected) + tm.assert_series_equal(result2, result3) + tm.assert_series_equal(result2, result4) # list selection result1 = indexer_sl(s)[[0.0, 5, 10]]