diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index f155fb27d0de5..7f81f040e92d4 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -395,6 +395,7 @@ Other Deprecations - Deprecated strings ``T``, ``S``, ``L``, ``U``, and ``N`` denoting frequencies in :class:`Minute`, :class:`Second`, :class:`Milli`, :class:`Micro`, :class:`Nano` (:issue:`52536`) - Deprecated the ``errors="ignore"`` option in :func:`to_datetime`, :func:`to_timedelta`, and :func:`to_numeric`; explicitly catch exceptions instead (:issue:`54467`) - Deprecated the ``fastpath`` keyword in the :class:`Series` constructor (:issue:`20110`) +- Deprecated the ``kind`` keyword in :meth:`Series.resample` and :meth:`DataFrame.resample`, explicitly cast the object's ``index`` instead (:issue:`55895`) - Deprecated the ``ordinal`` keyword in :class:`PeriodIndex`, use :meth:`PeriodIndex.from_ordinals` instead (:issue:`55960`) - Deprecated the extension test classes ``BaseNoReduceTests``, ``BaseBooleanReduceTests``, and ``BaseNumericReduceTests``, use ``BaseReduceTests`` instead (:issue:`54663`) - Deprecated the option ``mode.data_manager`` and the ``ArrayManager``; only the ``BlockManager`` will be available in future versions (:issue:`55043`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0d95d197815d3..c4b333c8a22ca 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -9217,7 +9217,7 @@ def resample( closed: Literal["right", "left"] | None = None, label: Literal["right", "left"] | None = None, convention: Literal["start", "end", "s", "e"] = "start", - kind: Literal["timestamp", "period"] | None = None, + kind: Literal["timestamp", "period"] | None | lib.NoDefault = lib.no_default, on: Level | None = None, level: Level | None = None, origin: str | TimestampConvertibleTypes = "start_day", @@ -9259,6 +9259,9 @@ def resample( `DateTimeIndex` or 'period' to convert it to a `PeriodIndex`. By default the input representation is retained. + .. deprecated:: 2.2.0 + Convert index to desired type explicitly instead. + on : str, optional For a DataFrame, column to use instead of index for resampling. Column must be datetime-like. @@ -9616,6 +9619,18 @@ def resample( else: axis = 0 + if kind is not lib.no_default: + # GH#55895 + warnings.warn( + f"The 'kind' keyword in {type(self).__name__}.resample is " + "deprecated and will be removed in a future version. " + "Explicitly cast the index to the desired type instead", + FutureWarning, + stacklevel=find_stack_level(), + ) + else: + kind = None + return get_resampler( cast("Series | DataFrame", self), freq=rule, diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py index 22cd0621fd4c4..bf56f054812e0 100644 --- a/pandas/tests/io/excel/test_writers.py +++ b/pandas/tests/io/excel/test_writers.py @@ -767,7 +767,9 @@ def test_to_excel_timedelta(self, path): tm.assert_frame_equal(expected, recons) def test_to_excel_periodindex(self, path): - xp = tm.makeTimeDataFrame()[:5].resample("ME", kind="period").mean() + # xp has a PeriodIndex + df = tm.makeTimeDataFrame()[:5] + xp = df.resample("ME").mean().to_period("M") xp.to_excel(path, sheet_name="sht1") diff --git a/pandas/tests/resample/test_datetime_index.py b/pandas/tests/resample/test_datetime_index.py index 98cd7d7ae22f6..865c02798c648 100644 --- a/pandas/tests/resample/test_datetime_index.py +++ b/pandas/tests/resample/test_datetime_index.py @@ -455,7 +455,9 @@ def test_resample_frame_basic_M_A(freq, unit): def test_resample_frame_basic_kind(freq, unit): df = tm.makeTimeDataFrame() df.index = df.index.as_unit(unit) - df.resample(freq, kind="period").mean() + msg = "The 'kind' keyword in DataFrame.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + df.resample(freq, kind="period").mean() def test_resample_upsample(unit): @@ -687,7 +689,9 @@ def test_resample_timestamp_to_period( ts = simple_date_range_series("1/1/1990", "1/1/2000") ts.index = ts.index.as_unit(unit) - result = ts.resample(freq, kind="period").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = ts.resample(freq, kind="period").mean() expected = ts.resample(freq).mean() expected.index = period_range(**expected_kwargs) tm.assert_series_equal(result, expected) @@ -1020,7 +1024,9 @@ def test_resample_to_period_monthly_buglet(unit): rng = date_range("1/1/2000", "12/31/2000").as_unit(unit) ts = Series(np.random.default_rng(2).standard_normal(len(rng)), index=rng) - result = ts.resample("ME", kind="period").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = ts.resample("ME", kind="period").mean() exp_index = period_range("Jan-2000", "Dec-2000", freq="M") tm.assert_index_equal(result.index, exp_index) @@ -1139,14 +1145,18 @@ def test_resample_anchored_intraday(unit): df = DataFrame(rng.month, index=rng) result = df.resample("ME").mean() - expected = df.resample("ME", kind="period").mean().to_timestamp(how="end") + msg = "The 'kind' keyword in DataFrame.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + expected = df.resample("ME", kind="period").mean().to_timestamp(how="end") expected.index += Timedelta(1, "ns") - Timedelta(1, "D") expected.index = expected.index.as_unit(unit)._with_freq("infer") assert expected.index.freq == "ME" tm.assert_frame_equal(result, expected) result = df.resample("ME", closed="left").mean() - exp = df.shift(1, freq="D").resample("ME", kind="period").mean() + msg = "The 'kind' keyword in DataFrame.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + exp = df.shift(1, freq="D").resample("ME", kind="period").mean() exp = exp.to_timestamp(how="end") exp.index = exp.index + Timedelta(1, "ns") - Timedelta(1, "D") @@ -1160,7 +1170,9 @@ def test_resample_anchored_intraday2(unit): df = DataFrame(rng.month, index=rng) result = df.resample("QE").mean() - expected = df.resample("QE", kind="period").mean().to_timestamp(how="end") + msg = "The 'kind' keyword in DataFrame.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + expected = df.resample("QE", kind="period").mean().to_timestamp(how="end") expected.index += Timedelta(1, "ns") - Timedelta(1, "D") expected.index._data.freq = "QE" expected.index._freq = lib.no_default @@ -1168,7 +1180,11 @@ def test_resample_anchored_intraday2(unit): tm.assert_frame_equal(result, expected) result = df.resample("QE", closed="left").mean() - expected = df.shift(1, freq="D").resample("QE", kind="period", closed="left").mean() + msg = "The 'kind' keyword in DataFrame.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + expected = ( + df.shift(1, freq="D").resample("QE", kind="period", closed="left").mean() + ) expected = expected.to_timestamp(how="end") expected.index += Timedelta(1, "ns") - Timedelta(1, "D") expected.index._data.freq = "QE" @@ -1225,7 +1241,9 @@ def test_corner_cases_date(simple_date_range_series, unit): # resample to periods ts = simple_date_range_series("2000-04-28", "2000-04-30 11:00", freq="h") ts.index = ts.index.as_unit(unit) - result = ts.resample("ME", kind="period").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = ts.resample("ME", kind="period").mean() assert len(result) == 1 assert result.index[0] == Period("2000-04", freq="M") diff --git a/pandas/tests/resample/test_period_index.py b/pandas/tests/resample/test_period_index.py index 5d233a940de2f..b66c2ff02a35d 100644 --- a/pandas/tests/resample/test_period_index.py +++ b/pandas/tests/resample/test_period_index.py @@ -77,7 +77,9 @@ def test_asfreq(self, series_and_frame, freq, kind): end = (obj.index[-1] + obj.index.freq).to_timestamp(how="start") new_index = date_range(start=start, end=end, freq=freq, inclusive="left") expected = obj.to_timestamp().reindex(new_index).to_period(freq) - result = obj.resample(freq, kind=kind).asfreq() + msg = "The 'kind' keyword in (Series|DataFrame).resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = obj.resample(freq, kind=kind).asfreq() tm.assert_almost_equal(result, expected) def test_asfreq_fill_value(self, series): @@ -90,7 +92,9 @@ def test_asfreq_fill_value(self, series): freq="1h", ) expected = s.to_timestamp().reindex(new_index, fill_value=4.0) - result = s.resample("1h", kind="timestamp").asfreq(fill_value=4.0) + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = s.resample("1h", kind="timestamp").asfreq(fill_value=4.0) tm.assert_series_equal(result, expected) frame = s.to_frame("value") @@ -100,7 +104,9 @@ def test_asfreq_fill_value(self, series): freq="1h", ) expected = frame.to_timestamp().reindex(new_index, fill_value=3.0) - result = frame.resample("1h", kind="timestamp").asfreq(fill_value=3.0) + msg = "The 'kind' keyword in DataFrame.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = frame.resample("1h", kind="timestamp").asfreq(fill_value=3.0) tm.assert_frame_equal(result, expected) @pytest.mark.parametrize("freq", ["h", "12h", "2D", "W"]) @@ -119,8 +125,10 @@ def test_selection(self, index, freq, kind, kwargs): r"not currently supported, use \.set_index\(\.\.\.\) to " "explicitly set index" ) + depr_msg = "The 'kind' keyword in DataFrame.resample is deprecated" with pytest.raises(NotImplementedError, match=msg): - df.resample(freq, kind=kind, **kwargs) + with tm.assert_produces_warning(FutureWarning, match=depr_msg): + df.resample(freq, kind=kind, **kwargs) @pytest.mark.parametrize("month", MONTHS) @pytest.mark.parametrize("meth", ["ffill", "bfill"]) @@ -250,9 +258,12 @@ def test_resample_basic(self): name="idx", ) expected = Series([34.5, 79.5], index=index) - result = s.to_period().resample("min", kind="period").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = s.to_period().resample("min", kind="period").mean() tm.assert_series_equal(result, expected) - result2 = s.resample("min", kind="period").mean() + with tm.assert_produces_warning(FutureWarning, match=msg): + result2 = s.resample("min", kind="period").mean() tm.assert_series_equal(result2, expected) @pytest.mark.parametrize( @@ -307,7 +318,9 @@ def test_with_local_timezone(self, tz): series = Series(1, index=index) series = series.tz_convert(local_timezone) - result = series.resample("D", kind="period").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = series.resample("D", kind="period").mean() # Create the expected series # Index is moved back a day with the timezone conversion from UTC to @@ -406,7 +419,9 @@ def test_weekly_upsample(self, day, target, convention, simple_period_range_seri def test_resample_to_timestamps(self, simple_period_range_series): ts = simple_period_range_series("1/1/1990", "12/31/1995", freq="M") - result = ts.resample("Y-DEC", kind="timestamp").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = ts.resample("Y-DEC", kind="timestamp").mean() expected = ts.to_timestamp(how="start").resample("YE-DEC").mean() tm.assert_series_equal(result, expected) @@ -466,7 +481,9 @@ def test_resample_5minute(self, freq, kind): expected = ts.to_timestamp().resample(freq).mean() if kind != "timestamp": expected = expected.to_period(freq) - result = ts.resample(freq, kind=kind).mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = ts.resample(freq, kind=kind).mean() tm.assert_series_equal(result, expected) def test_upsample_daily_business_daily(self, simple_period_range_series): @@ -540,7 +557,9 @@ def test_resample_tz_localized2(self): tm.assert_series_equal(result, expected) # for good measure - result = s.resample("D", kind="period").mean() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = s.resample("D", kind="period").mean() ex_index = period_range("2001-09-20", periods=1, freq="D") expected = Series([1.5], index=ex_index) tm.assert_series_equal(result, expected) @@ -785,7 +804,9 @@ def test_upsampling_ohlc(self, freq, period_mult, kind): # of the last original period, so extend accordingly: new_index = period_range(start="2000", freq=freq, periods=period_mult * len(pi)) expected = expected.reindex(new_index) - result = s.resample(freq, kind=kind).ohlc() + msg = "The 'kind' keyword in Series.resample is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + result = s.resample(freq, kind=kind).ohlc() tm.assert_frame_equal(result, expected) @pytest.mark.parametrize(