Skip to content

Commit

Permalink
DEPR: int slicing always positional (#53338)
Browse files Browse the repository at this point in the history
* DEPR: int slicing always positional

* update doc

* okwarning
  • Loading branch information
jbrockmendel authored Aug 4, 2023
1 parent 5be4339 commit 39f9b33
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 14 deletions.
2 changes: 1 addition & 1 deletion doc/source/user_guide/missing_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ at the new values.
# interpolate at new_index
new_index = ser.index.union(pd.Index([49.25, 49.5, 49.75, 50.25, 50.5, 50.75]))
interp_s = ser.reindex(new_index).interpolate(method="pchip")
interp_s[49:51]
interp_s.loc[49:51]
.. _scipy: https://scipy.org/
.. _documentation: https://docs.scipy.org/doc/scipy/reference/interpolate.html#univariate-interpolation
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.13.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ Float64Index API change
Slicing is ALWAYS on the values of the index, for ``[],ix,loc`` and ALWAYS positional with ``iloc``

.. ipython:: python
:okwarning:
s[2:4]
s.loc[2:4]
Expand Down
1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ Other Deprecations
- Deprecated the "method" and "limit" keywords in ``ExtensionArray.fillna``, implement and use ``pad_or_backfill`` instead (:issue:`53621`)
- Deprecated the "method" and "limit" keywords on :meth:`Series.fillna`, :meth:`DataFrame.fillna`, :meth:`SeriesGroupBy.fillna`, :meth:`DataFrameGroupBy.fillna`, and :meth:`Resampler.fillna`, use ``obj.bfill()`` or ``obj.ffill()`` instead (:issue:`53394`)
- Deprecated the ``method`` and ``limit`` keywords in :meth:`DataFrame.replace` and :meth:`Series.replace` (:issue:`33302`)
- Deprecated the 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, in a future version this will be treated as *positional* indexing (:issue:`49612`)
- Deprecated the use of non-supported datetime64 and timedelta64 resolutions with :func:`pandas.array`. Supported resolutions are: "s", "ms", "us", "ns" resolutions (:issue:`53058`)
- Deprecated values "pad", "ffill", "bfill", "backfill" for :meth:`Series.interpolate` and :meth:`DataFrame.interpolate`, use ``obj.ffill()`` or ``obj.bfill()`` instead (:issue:`53581`)
- Deprecated the behavior of :meth:`Index.argmax`, :meth:`Index.argmin`, :meth:`Series.argmax`, :meth:`Series.argmin` with either all-NAs and skipna=True or any-NAs and skipna=False returning -1; in a future version this will raise ``ValueError`` (:issue:`33941`, :issue:`33942`)
Expand Down
20 changes: 17 additions & 3 deletions pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4212,16 +4212,30 @@ def _convert_slice_indexer(self, key: slice, kind: Literal["loc", "getitem"]):
# potentially cast the bounds to integers
start, stop, step = key.start, key.stop, key.step

# figure out if this is a positional indexer
is_index_slice = is_valid_positional_slice(key)

# 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)

# figure out if this is a positional indexer
is_index_slice = is_valid_positional_slice(key)

if kind == "getitem":
# called from the getitem slicers, validate that we are in fact integers
if is_index_slice:
Expand Down
4 changes: 3 additions & 1 deletion pandas/tests/frame/indexing/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,9 @@ def test_getitem_setitem_float_labels(self, using_array_manager):
tm.assert_frame_equal(result, expected)

df.loc[1:2] = 0
result = df[1: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]
assert (result == 0).all().all()

# #2727
Expand Down
9 changes: 7 additions & 2 deletions pandas/tests/indexing/test_floats.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +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'
result1 = indexer_sl(s)[2:5]
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]
Expand All @@ -498,7 +502,8 @@ def test_floating_misc(self, indexer_sl):
tm.assert_series_equal(result1, result4)

expected = Series([1, 2], index=[2.5, 5.0])
result = indexer_sl(s)[2:5]
with tm.assert_produces_warning(warn, match=msg):
result = indexer_sl(s)[2:5]

tm.assert_series_equal(result, expected)

Expand Down
14 changes: 7 additions & 7 deletions pandas/tests/series/methods/test_interpolate.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def test_interpolate_cubicspline(self):
new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
float
)
result = ser.reindex(new_index).interpolate(method="cubicspline")[1:3]
result = ser.reindex(new_index).interpolate(method="cubicspline").loc[1:3]
tm.assert_series_equal(result, expected)

def test_interpolate_pchip(self):
Expand All @@ -142,7 +142,7 @@ def test_interpolate_pchip(self):
).astype(float)
interp_s = ser.reindex(new_index).interpolate(method="pchip")
# does not blow up, GH5977
interp_s[49:51]
interp_s.loc[49:51]

def test_interpolate_akima(self):
pytest.importorskip("scipy")
Expand All @@ -157,7 +157,7 @@ def test_interpolate_akima(self):
float
)
interp_s = ser.reindex(new_index).interpolate(method="akima")
tm.assert_series_equal(interp_s[1:3], expected)
tm.assert_series_equal(interp_s.loc[1:3], expected)

# interpolate at new_index where `der` is a non-zero int
expected = Series(
Expand All @@ -168,7 +168,7 @@ def test_interpolate_akima(self):
float
)
interp_s = ser.reindex(new_index).interpolate(method="akima", der=1)
tm.assert_series_equal(interp_s[1:3], expected)
tm.assert_series_equal(interp_s.loc[1:3], expected)

def test_interpolate_piecewise_polynomial(self):
pytest.importorskip("scipy")
Expand All @@ -183,7 +183,7 @@ def test_interpolate_piecewise_polynomial(self):
float
)
interp_s = ser.reindex(new_index).interpolate(method="piecewise_polynomial")
tm.assert_series_equal(interp_s[1:3], expected)
tm.assert_series_equal(interp_s.loc[1:3], expected)

def test_interpolate_from_derivatives(self):
pytest.importorskip("scipy")
Expand All @@ -198,7 +198,7 @@ def test_interpolate_from_derivatives(self):
float
)
interp_s = ser.reindex(new_index).interpolate(method="from_derivatives")
tm.assert_series_equal(interp_s[1:3], expected)
tm.assert_series_equal(interp_s.loc[1:3], expected)

@pytest.mark.parametrize(
"kwargs",
Expand All @@ -218,7 +218,7 @@ def test_interpolate_corners(self, kwargs):

def test_interpolate_index_values(self):
s = Series(np.nan, index=np.sort(np.random.default_rng(2).random(30)))
s[::3] = np.random.default_rng(2).standard_normal(10)
s.loc[::3] = np.random.default_rng(2).standard_normal(10)

vals = s.index.values.astype(float)

Expand Down

0 comments on commit 39f9b33

Please sign in to comment.