Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLN: enforce deprecation of the kind keyword on df.resample/ser.resample #58125

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -215,6 +215,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 @@ -8615,7 +8615,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 @@ -8648,14 +8647,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 @@ -8947,18 +8938,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 @@ -8976,7 +8955,6 @@ def resample(
freq=rule,
label=label,
closed=closed,
kind=kind,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont see a diff in pandas.core.resample; doesn't the keyword need to be removed there too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, my mistake. I removed the keyword kind from get_resampler

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't all/most of the kind keywords in resample.py be removable?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment. Yes, it was my mistake; kind can be removed from Resampler and TimeGrouper. I have updated this PR. Could you please take a look?

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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think you can remove this test entirely

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, done



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