Skip to content

Commit 5dac942

Browse files
jbrockmendelmroeschke
authored andcommitted
DEPR: int slicing always positional (pandas-dev#53338)
* DEPR: int slicing always positional * update doc * okwarning
1 parent 427bb68 commit 5dac942

File tree

7 files changed

+37
-14
lines changed

7 files changed

+37
-14
lines changed

doc/source/user_guide/missing_data.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ at the new values.
436436
# interpolate at new_index
437437
new_index = ser.index.union(pd.Index([49.25, 49.5, 49.75, 50.25, 50.5, 50.75]))
438438
interp_s = ser.reindex(new_index).interpolate(method="pchip")
439-
interp_s[49:51]
439+
interp_s.loc[49:51]
440440
441441
.. _scipy: https://scipy.org/
442442
.. _documentation: https://docs.scipy.org/doc/scipy/reference/interpolate.html#univariate-interpolation

doc/source/whatsnew/v0.13.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ Float64Index API change
343343
Slicing is ALWAYS on the values of the index, for ``[],ix,loc`` and ALWAYS positional with ``iloc``
344344

345345
.. ipython:: python
346+
:okwarning:
346347
347348
s[2:4]
348349
s.loc[2:4]

doc/source/whatsnew/v2.1.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@ Other Deprecations
553553
- Deprecated the "method" and "limit" keywords in ``ExtensionArray.fillna``, implement and use ``pad_or_backfill`` instead (:issue:`53621`)
554554
- 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`)
555555
- Deprecated the ``method`` and ``limit`` keywords in :meth:`DataFrame.replace` and :meth:`Series.replace` (:issue:`33302`)
556+
- 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`)
556557
- Deprecated the use of non-supported datetime64 and timedelta64 resolutions with :func:`pandas.array`. Supported resolutions are: "s", "ms", "us", "ns" resolutions (:issue:`53058`)
557558
- Deprecated values "pad", "ffill", "bfill", "backfill" for :meth:`Series.interpolate` and :meth:`DataFrame.interpolate`, use ``obj.ffill()`` or ``obj.bfill()`` instead (:issue:`53581`)
558559
- 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`)

pandas/core/indexes/base.py

+17-3
Original file line numberDiff line numberDiff line change
@@ -4211,16 +4211,30 @@ def _convert_slice_indexer(self, key: slice, kind: Literal["loc", "getitem"]):
42114211
# potentially cast the bounds to integers
42124212
start, stop, step = key.start, key.stop, key.step
42134213

4214+
# figure out if this is a positional indexer
4215+
is_index_slice = is_valid_positional_slice(key)
4216+
42144217
# TODO(GH#50617): once Series.__[gs]etitem__ is removed we should be able
42154218
# to simplify this.
42164219
if lib.is_np_dtype(self.dtype, "f"):
42174220
# We always treat __getitem__ slicing as label-based
42184221
# translate to locations
4222+
if kind == "getitem" and is_index_slice and not start == stop and step != 0:
4223+
# exclude step=0 from the warning because it will raise anyway
4224+
# start/stop both None e.g. [:] or [::-1] won't change.
4225+
# exclude start==stop since it will be empty either way, or
4226+
# will be [:] or [::-1] which won't change
4227+
warnings.warn(
4228+
# GH#49612
4229+
"The behavior of obj[i:j] with a float-dtype index is "
4230+
"deprecated. In a future version, this will be treated as "
4231+
"positional instead of label-based. For label-based slicing, "
4232+
"use obj.loc[i:j] instead",
4233+
FutureWarning,
4234+
stacklevel=find_stack_level(),
4235+
)
42194236
return self.slice_indexer(start, stop, step)
42204237

4221-
# figure out if this is a positional indexer
4222-
is_index_slice = is_valid_positional_slice(key)
4223-
42244238
if kind == "getitem":
42254239
# called from the getitem slicers, validate that we are in fact integers
42264240
if is_index_slice:

pandas/tests/frame/indexing/test_indexing.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,9 @@ def test_getitem_setitem_float_labels(self, using_array_manager):
755755
tm.assert_frame_equal(result, expected)
756756

757757
df.loc[1:2] = 0
758-
result = df[1:2]
758+
msg = r"The behavior of obj\[i:j\] with a float-dtype index"
759+
with tm.assert_produces_warning(FutureWarning, match=msg):
760+
result = df[1:2]
759761
assert (result == 0).all().all()
760762

761763
# #2727

pandas/tests/indexing/test_floats.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,12 @@ def test_floating_misc(self, indexer_sl):
488488
for fancy_idx in [[5, 0], np.array([5, 0])]:
489489
tm.assert_series_equal(indexer_sl(s)[fancy_idx], expected)
490490

491+
warn = FutureWarning if indexer_sl is tm.setitem else None
492+
msg = r"The behavior of obj\[i:j\] with a float-dtype index"
493+
491494
# all should return the same as we are slicing 'the same'
492-
result1 = indexer_sl(s)[2:5]
495+
with tm.assert_produces_warning(warn, match=msg):
496+
result1 = indexer_sl(s)[2:5]
493497
result2 = indexer_sl(s)[2.0:5.0]
494498
result3 = indexer_sl(s)[2.0:5]
495499
result4 = indexer_sl(s)[2.1:5]
@@ -498,7 +502,8 @@ def test_floating_misc(self, indexer_sl):
498502
tm.assert_series_equal(result1, result4)
499503

500504
expected = Series([1, 2], index=[2.5, 5.0])
501-
result = indexer_sl(s)[2:5]
505+
with tm.assert_produces_warning(warn, match=msg):
506+
result = indexer_sl(s)[2:5]
502507

503508
tm.assert_series_equal(result, expected)
504509

pandas/tests/series/methods/test_interpolate.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def test_interpolate_cubicspline(self):
129129
new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
130130
float
131131
)
132-
result = ser.reindex(new_index).interpolate(method="cubicspline")[1:3]
132+
result = ser.reindex(new_index).interpolate(method="cubicspline").loc[1:3]
133133
tm.assert_series_equal(result, expected)
134134

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

147147
def test_interpolate_akima(self):
148148
pytest.importorskip("scipy")
@@ -157,7 +157,7 @@ def test_interpolate_akima(self):
157157
float
158158
)
159159
interp_s = ser.reindex(new_index).interpolate(method="akima")
160-
tm.assert_series_equal(interp_s[1:3], expected)
160+
tm.assert_series_equal(interp_s.loc[1:3], expected)
161161

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

173173
def test_interpolate_piecewise_polynomial(self):
174174
pytest.importorskip("scipy")
@@ -183,7 +183,7 @@ def test_interpolate_piecewise_polynomial(self):
183183
float
184184
)
185185
interp_s = ser.reindex(new_index).interpolate(method="piecewise_polynomial")
186-
tm.assert_series_equal(interp_s[1:3], expected)
186+
tm.assert_series_equal(interp_s.loc[1:3], expected)
187187

188188
def test_interpolate_from_derivatives(self):
189189
pytest.importorskip("scipy")
@@ -198,7 +198,7 @@ def test_interpolate_from_derivatives(self):
198198
float
199199
)
200200
interp_s = ser.reindex(new_index).interpolate(method="from_derivatives")
201-
tm.assert_series_equal(interp_s[1:3], expected)
201+
tm.assert_series_equal(interp_s.loc[1:3], expected)
202202

203203
@pytest.mark.parametrize(
204204
"kwargs",
@@ -218,7 +218,7 @@ def test_interpolate_corners(self, kwargs):
218218

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

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

0 commit comments

Comments
 (0)