Skip to content

Commit

Permalink
CLN: enforce deprecation of the kind keyword on df.resample/ser.res…
Browse files Browse the repository at this point in the history
…ample (pandas-dev#58125)

* enforced deprecation of the kind keyword on df.resample/ser.resample

* fix tests

* fix tests

* fix tests

* add a note to v3.0.0

* return a blank line in resample.py back

* remove leftover

* remove kind from get_resampler, delete test

* remove kwd kind from _get_resampler, fix test

* remove kwd kind from the class Resampler

* remove kind from TimeGrouper

* inline the parameter freq in test_resample_5minute
  • Loading branch information
natmokval authored and pmhatre1 committed May 7, 2024
1 parent 420a101 commit c06a0b5
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 168 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ Removal of prior version deprecations/changes
- Disallow units other than "s", "ms", "us", "ns" for datetime64 and timedelta64 dtypes in :func:`array` (:issue:`53817`)
- Removed "freq" keyword from :class:`PeriodArray` constructor, use "dtype" instead (:issue:`52462`)
- Removed 'fastpath' keyword in :class:`Categorical` constructor (:issue:`20110`)
- Removed 'kind' keyword in :meth:`Series.resample` and :meth:`DataFrame.resample` (:issue:`58125`)
- Removed alias :class:`arrays.PandasArray` for :class:`arrays.NumpyExtensionArray` (:issue:`53694`)
- Removed deprecated "method" and "limit" keywords from :meth:`Series.replace` and :meth:`DataFrame.replace` (:issue:`53492`)
- Removed extension test classes ``BaseNoReduceTests``, ``BaseNumericReduceTests``, ``BaseBooleanReduceTests`` (:issue:`54663`)
Expand Down
22 changes: 0 additions & 22 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8662,7 +8662,6 @@ def resample(
closed: Literal["right", "left"] | None = None,
label: Literal["right", "left"] | None = None,
convention: Literal["start", "end", "s", "e"] | lib.NoDefault = lib.no_default,
kind: Literal["timestamp", "period"] | None | lib.NoDefault = lib.no_default,
on: Level | None = None,
level: Level | None = None,
origin: str | TimestampConvertibleTypes = "start_day",
Expand Down Expand Up @@ -8695,14 +8694,6 @@ def resample(
.. deprecated:: 2.2.0
Convert PeriodIndex to DatetimeIndex before resampling instead.
kind : {{'timestamp', 'period'}}, optional, default None
Pass 'timestamp' to convert the resulting index to a
`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.
Expand Down Expand Up @@ -8994,18 +8985,6 @@ def resample(
"""
from pandas.core.resample import get_resampler

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

if convention is not lib.no_default:
warnings.warn(
f"The 'convention' keyword in {type(self).__name__}.resample is "
Expand All @@ -9023,7 +9002,6 @@ def resample(
freq=rule,
label=label,
closed=closed,
kind=kind,
convention=convention,
key=on,
level=level,
Expand Down
44 changes: 13 additions & 31 deletions pandas/core/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,6 @@ class Resampler(BaseGroupBy, PandasObject):
----------
obj : Series or DataFrame
groupby : TimeGrouper
kind : str or None
'period', 'timestamp' to override default index treatment
Returns
-------
Expand All @@ -154,7 +152,6 @@ class Resampler(BaseGroupBy, PandasObject):
"closed",
"label",
"convention",
"kind",
"origin",
"offset",
]
Expand All @@ -163,7 +160,6 @@ def __init__(
self,
obj: NDFrame,
timegrouper: TimeGrouper,
kind=None,
*,
gpr_index: Index,
group_keys: bool = False,
Expand All @@ -173,7 +169,6 @@ def __init__(
self._timegrouper = timegrouper
self.keys = None
self.sort = True
self.kind = kind
self.group_keys = group_keys
self.as_index = True
self.include_groups = include_groups
Expand Down Expand Up @@ -1580,7 +1575,7 @@ def _resampler_for_grouping(self) -> type[DatetimeIndexResamplerGroupby]:

def _get_binner_for_time(self):
# this is how we are actually creating the bins
if self.kind == "period":
if isinstance(self.ax, PeriodIndex):
return self._timegrouper._get_time_period_bins(self.ax)
return self._timegrouper._get_time_bins(self.ax)

Expand Down Expand Up @@ -1678,7 +1673,9 @@ def _wrap_result(self, result):

# we may have a different kind that we were asked originally
# convert if needed
if self.kind == "period" and not isinstance(result.index, PeriodIndex):
if isinstance(self.ax, PeriodIndex) and not isinstance(
result.index, PeriodIndex
):
if isinstance(result.index, MultiIndex):
# GH 24103 - e.g. groupby resample
if not isinstance(result.index.levels[-1], PeriodIndex):
Expand Down Expand Up @@ -1719,7 +1716,7 @@ def _resampler_for_grouping(self):
return PeriodIndexResamplerGroupby

def _get_binner_for_time(self):
if self.kind == "timestamp":
if isinstance(self.ax, DatetimeIndex):
return super()._get_binner_for_time()
return self._timegrouper._get_period_bins(self.ax)

Expand All @@ -1736,7 +1733,7 @@ def _convert_obj(self, obj: NDFrameT) -> NDFrameT:
raise NotImplementedError(msg)

# convert to timestamp
if self.kind == "timestamp":
if isinstance(obj, DatetimeIndex):
obj = obj.to_timestamp(how=self.convention)

return obj
Expand All @@ -1751,7 +1748,7 @@ def _downsample(self, how, **kwargs):
**kwargs : kw args passed to how function
"""
# we may need to actually resample as if we are timestamps
if self.kind == "timestamp":
if isinstance(self.ax, DatetimeIndex):
return super()._downsample(how, **kwargs)

ax = self.ax
Expand Down Expand Up @@ -1788,7 +1785,7 @@ def _upsample(self, method, limit: int | None = None, fill_value=None):
Value to use for missing values.
"""
# we may need to actually resample as if we are timestamps
if self.kind == "timestamp":
if isinstance(self.ax, DatetimeIndex):
return super()._upsample(method, limit=limit, fill_value=fill_value)

ax = self.ax
Expand Down Expand Up @@ -1860,12 +1857,12 @@ def _resampler_cls(self):
return TimedeltaIndexResampler


def get_resampler(obj: Series | DataFrame, kind=None, **kwds) -> Resampler:
def get_resampler(obj: Series | DataFrame, **kwds) -> Resampler:
"""
Create a TimeGrouper and return our resampler.
"""
tg = TimeGrouper(obj, **kwds) # type: ignore[arg-type]
return tg._get_resampler(obj, kind=kind)
return tg._get_resampler(obj)


get_resampler.__doc__ = Resampler.__doc__
Expand All @@ -1877,7 +1874,6 @@ def get_resampler_for_grouping(
how=None,
fill_method=None,
limit: int | None = None,
kind=None,
on=None,
include_groups: bool = True,
**kwargs,
Expand All @@ -1887,7 +1883,7 @@ def get_resampler_for_grouping(
"""
# .resample uses 'on' similar to how .groupby uses 'key'
tg = TimeGrouper(freq=rule, key=on, **kwargs)
resampler = tg._get_resampler(groupby.obj, kind=kind)
resampler = tg._get_resampler(groupby.obj)
return resampler._get_resampler_for_grouping(
groupby=groupby, include_groups=include_groups, key=tg.key
)
Expand All @@ -1910,7 +1906,6 @@ class TimeGrouper(Grouper):
"closed",
"label",
"how",
"kind",
"convention",
"origin",
"offset",
Expand All @@ -1928,7 +1923,6 @@ def __init__(
how: str = "mean",
fill_method=None,
limit: int | None = None,
kind: str | None = None,
convention: Literal["start", "end", "e", "s"] | None = None,
origin: Literal["epoch", "start", "start_day", "end", "end_day"]
| TimestampConvertibleTypes = "start_day",
Expand Down Expand Up @@ -1986,7 +1980,6 @@ def __init__(

self.closed = closed
self.label = label
self.kind = kind
self.convention = convention if convention is not None else "e"
self.how = how
self.fill_method = fill_method
Expand Down Expand Up @@ -2024,15 +2017,13 @@ def __init__(

super().__init__(freq=freq, key=key, **kwargs)

def _get_resampler(self, obj: NDFrame, kind=None) -> Resampler:
def _get_resampler(self, obj: NDFrame) -> Resampler:
"""
Return my resampler or raise if we have an invalid axis.
Parameters
----------
obj : Series or DataFrame
kind : string, optional
'period','timestamp','timedelta' are valid
Returns
-------
Expand All @@ -2048,11 +2039,10 @@ def _get_resampler(self, obj: NDFrame, kind=None) -> Resampler:
return DatetimeIndexResampler(
obj,
timegrouper=self,
kind=kind,
group_keys=self.group_keys,
gpr_index=ax,
)
elif isinstance(ax, PeriodIndex) or kind == "period":
elif isinstance(ax, PeriodIndex):
if isinstance(ax, PeriodIndex):
# GH#53481
warnings.warn(
Expand All @@ -2061,17 +2051,9 @@ def _get_resampler(self, obj: NDFrame, kind=None) -> Resampler:
FutureWarning,
stacklevel=find_stack_level(),
)
else:
warnings.warn(
"Resampling with kind='period' is deprecated. "
"Use datetime paths instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return PeriodIndexResampler(
obj,
timegrouper=self,
kind=kind,
group_keys=self.group_keys,
gpr_index=ax,
)
Expand Down
46 changes: 10 additions & 36 deletions pandas/tests/resample/test_datetime_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,19 +441,6 @@ def test_resample_frame_basic_M_A(freq, unit):
tm.assert_series_equal(result["A"], df["A"].resample(freq).mean())


@pytest.mark.parametrize("freq", ["W-WED", "ME"])
def test_resample_frame_basic_kind(freq, unit):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
)
df.index = df.index.as_unit(unit)
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):
# from daily
dti = date_range(
Expand Down Expand Up @@ -665,9 +652,7 @@ def test_resample_timestamp_to_period(
ts = simple_date_range_series("1/1/1990", "1/1/2000")
ts.index = ts.index.as_unit(unit)

msg = "The 'kind' keyword in Series.resample is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ts.resample(freq, kind="period").mean()
result = ts.resample(freq).mean().to_period()
expected = ts.resample(freq).mean()
expected.index = period_range(**expected_kwargs)
tm.assert_series_equal(result, expected)
Expand Down Expand Up @@ -985,9 +970,7 @@ 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)

msg = "The 'kind' keyword in Series.resample is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ts.resample("ME", kind="period").mean()
result = ts.resample("ME").mean().to_period()
exp_index = period_range("Jan-2000", "Dec-2000", freq="M")
tm.assert_index_equal(result.index, exp_index)

Expand Down Expand Up @@ -1109,18 +1092,15 @@ def test_resample_anchored_intraday(unit):
df = DataFrame(rng.month, index=rng)

result = df.resample("ME").mean()
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 = df.resample("ME").mean().to_period()
expected = expected.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()
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 = df.shift(1, freq="D").resample("ME").mean().to_period()
exp = exp.to_timestamp(how="end")

exp.index = exp.index + Timedelta(1, "ns") - Timedelta(1, "D")
Expand All @@ -1134,21 +1114,17 @@ def test_resample_anchored_intraday2(unit):
df = DataFrame(rng.month, index=rng)

result = df.resample("QE").mean()
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 = df.resample("QE").mean().to_period()
expected = expected.to_timestamp(how="end")
expected.index += Timedelta(1, "ns") - Timedelta(1, "D")
expected.index._data.freq = "QE"
expected.index._freq = lib.no_default
expected.index = expected.index.as_unit(unit)
tm.assert_frame_equal(result, expected)

result = df.resample("QE", 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 = df.shift(1, freq="D").resample("QE").mean()
expected = expected.to_period()
expected = expected.to_timestamp(how="end")
expected.index += Timedelta(1, "ns") - Timedelta(1, "D")
expected.index._data.freq = "QE"
Expand Down Expand Up @@ -1205,9 +1181,7 @@ 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)
msg = "The 'kind' keyword in Series.resample is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ts.resample("ME", kind="period").mean()
result = ts.resample("ME").mean().to_period()
assert len(result) == 1
assert result.index[0] == Period("2000-04", freq="M")

Expand Down
Loading

0 comments on commit c06a0b5

Please sign in to comment.