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

DEP: remove deprecated loffset and base args for resample and Grouper #49101

1 change: 1 addition & 0 deletions doc/source/whatsnew/v2.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ Removal of prior version deprecations/changes
- Changed behavior of :class:`DataFrame` constructor when passed a ``dtype`` (other than int) that the data cannot be cast to; it now raises instead of silently ignoring the dtype (:issue:`41733`)
- Changed the behavior of :class:`Series` constructor, it will no longer infer a datetime64 or timedelta64 dtype from string entries (:issue:`41731`)
- Changed behavior of :class:`Index` constructor when passed a ``SparseArray`` or ``SparseDtype`` to retain that dtype instead of casting to ``numpy.ndarray`` (:issue:`43930`)
- Removed the deprecated ``base`` and ``loffset`` arguments from :meth:`pandas.DataFrame.resample`, :meth:`pandas.Series.resample` and :class:`pandas.Grouper`. Use ``offset`` or ``origin`` instead (:issue:`31809`)
- Changed behavior of :meth:`DataFrame.any` and :meth:`DataFrame.all` with ``bool_only=True``; object-dtype columns with all-bool values will no longer be included, manually cast to ``bool`` dtype first (:issue:`46188`)
-

Expand Down
4 changes: 0 additions & 4 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -11336,8 +11336,6 @@ def resample(
label: str | None = None,
convention: str = "start",
kind: str | None = None,
loffset=None,
base: int | None = None,
on: Level = None,
level: Level = None,
origin: str | TimestampConvertibleTypes = "start_day",
Expand All @@ -11351,8 +11349,6 @@ def resample(
label=label,
convention=convention,
kind=kind,
loffset=loffset,
base=base,
on=on,
level=level,
origin=origin,
Expand Down
43 changes: 0 additions & 43 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -8454,8 +8454,6 @@ def resample(
label: str | None = None,
convention: str = "start",
kind: str | None = None,
loffset=None,
base: int | None = None,
on: Level = None,
level: Level = None,
origin: str | TimestampConvertibleTypes = "start_day",
Expand Down Expand Up @@ -8493,20 +8491,6 @@ def resample(
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.
loffset : timedelta, default None
Adjust the resampled time labels.

.. deprecated:: 1.1.0
You should add the loffset to the `df.index` after the resample.
See below.

base : int, default 0
For frequencies that evenly subdivide 1 day, the "origin" of the
aggregated intervals. For example, for '5min' frequency, base could
range from 0 through 4. Defaults to 0.

.. deprecated:: 1.1.0
The new arguments that you should use are 'offset' or 'origin'.

on : str, optional
For a DataFrame, column to use instead of index for resampling.
Expand Down Expand Up @@ -8842,31 +8826,6 @@ def resample(
2000-10-02 00:12:00 45
2000-10-02 00:29:00 45
Freq: 17T, dtype: int64

To replace the use of the deprecated `base` argument, you can now use `offset`,
in this example it is equivalent to have `base=2`:

>>> ts.resample('17min', offset='2min').sum()
2000-10-01 23:16:00 0
2000-10-01 23:33:00 9
2000-10-01 23:50:00 36
2000-10-02 00:07:00 39
2000-10-02 00:24:00 24
Freq: 17T, dtype: int64

To replace the use of the deprecated `loffset` argument:

>>> from pandas.tseries.frequencies import to_offset
>>> loffset = '19min'
>>> ts_out = ts.resample('17min').sum()
>>> ts_out.index = ts_out.index + to_offset(loffset)
>>> ts_out
2000-10-01 23:33:00 0
2000-10-01 23:50:00 9
2000-10-02 00:07:00 21
2000-10-02 00:24:00 54
2000-10-02 00:41:00 24
Freq: 17T, dtype: int64
"""
from pandas.core.resample import get_resampler

Expand All @@ -8878,9 +8837,7 @@ def resample(
closed=closed,
axis=axis,
kind=kind,
loffset=loffset,
convention=convention,
base=base,
key=on,
level=level,
origin=origin,
Expand Down
68 changes: 0 additions & 68 deletions pandas/core/groupby/grouper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
Iterator,
final,
)
import warnings

import numpy as np

Expand All @@ -23,7 +22,6 @@
)
from pandas.errors import InvalidIndexError
from pandas.util._decorators import cache_readonly
from pandas.util._exceptions import find_stack_level

from pandas.core.dtypes.common import (
is_categorical_dtype,
Expand Down Expand Up @@ -86,23 +84,6 @@ class Grouper:
Only when `freq` parameter is passed.
convention : {'start', 'end', 'e', 's'}
If grouper is PeriodIndex and `freq` parameter is passed.
base : int, default 0
Only when `freq` parameter is passed.
For frequencies that evenly subdivide 1 day, the "origin" of the
aggregated intervals. For example, for '5min' frequency, base could
range from 0 through 4. Defaults to 0.

.. deprecated:: 1.1.0
The new arguments that you should use are 'offset' or 'origin'.

loffset : str, DateOffset, timedelta object
Only when `freq` parameter is passed.

.. deprecated:: 1.1.0
loffset is only working for ``.resample(...)`` and not for
Grouper (:issue:`28302`).
However, loffset is also deprecated for ``.resample(...)``
See: :class:`DataFrame.resample`

origin : Timestamp or str, default 'start_day'
The timestamp on which to adjust the grouping. The timezone of origin must
Expand Down Expand Up @@ -266,7 +247,6 @@ def __new__(cls, *args, **kwargs):
if kwargs.get("freq") is not None:
from pandas.core.resample import TimeGrouper

_check_deprecated_resample_kwargs(kwargs, origin=cls)
cls = TimeGrouper
return super().__new__(cls)

Expand Down Expand Up @@ -954,51 +934,3 @@ def _convert_grouper(axis: Index, grouper):
return grouper
else:
return grouper


def _check_deprecated_resample_kwargs(kwargs, origin) -> None:
"""
Check for use of deprecated parameters in ``resample`` and related functions.

Raises the appropriate warnings if these parameters are detected.
Only sets an approximate ``stacklevel`` for the warnings (see #37603, #36629).

Parameters
----------
kwargs : dict
Dictionary of keyword arguments to check for deprecated parameters.
origin : object
From where this function is being called; either Grouper or TimeGrouper. Used
to determine an approximate stacklevel.
"""
# Deprecation warning of `base` and `loffset` since v1.1.0:
# we are raising the warning here to be able to set the `stacklevel`
# properly since we need to raise the `base` and `loffset` deprecation
# warning from three different cases:
# core/generic.py::NDFrame.resample
# core/groupby/groupby.py::GroupBy.resample
# core/groupby/grouper.py::Grouper
# raising these warnings from TimeGrouper directly would fail the test:
# tests/resample/test_deprecated.py::test_deprecating_on_loffset_and_base

if kwargs.get("base", None) is not None:
warnings.warn(
"'base' in .resample() and in Grouper() is deprecated.\n"
"The new arguments that you should use are 'offset' or 'origin'.\n"
'\n>>> df.resample(freq="3s", base=2)\n'
"\nbecomes:\n"
'\n>>> df.resample(freq="3s", offset="2s")\n',
FutureWarning,
stacklevel=find_stack_level(),
)
if kwargs.get("loffset", None) is not None:
warnings.warn(
"'loffset' in .resample() and in Grouper() is deprecated.\n"
'\n>>> df.resample(freq="3s", loffset="8H")\n'
"\nbecomes:\n"
"\n>>> from pandas.tseries.frequencies import to_offset"
'\n>>> df = df.resample(freq="3s").mean()'
'\n>>> df.index = df.index.to_timestamp() + to_offset("8H")\n',
FutureWarning,
stacklevel=find_stack_level(),
)
62 changes: 0 additions & 62 deletions pandas/core/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
is_superperiod,
)
from pandas.tseries.offsets import (
DateOffset,
Day,
Nano,
Tick,
Expand Down Expand Up @@ -139,7 +138,6 @@ class Resampler(BaseGroupBy, PandasObject):
"closed",
"label",
"convention",
"loffset",
"kind",
"origin",
"offset",
Expand Down Expand Up @@ -358,7 +356,6 @@ def aggregate(self, func=None, *args, **kwargs):
how = func
result = self._groupby_and_aggregate(how, *args, **kwargs)

result = self._apply_loffset(result)
return result

agg = aggregate
Expand Down Expand Up @@ -475,38 +472,8 @@ def _groupby_and_aggregate(self, how, *args, **kwargs):
# try to evaluate
result = grouped.apply(how, *args, **kwargs)

result = self._apply_loffset(result)
return self._wrap_result(result)

def _apply_loffset(self, result):
"""
If loffset is set, offset the result index.

This is NOT an idempotent routine, it will be applied
exactly once to the result.

Parameters
----------
result : Series or DataFrame
the result of resample
"""
# error: Cannot determine type of 'loffset'
needs_offset = (
isinstance(
self.loffset, # type: ignore[has-type]
(DateOffset, timedelta, np.timedelta64),
)
and isinstance(result.index, DatetimeIndex)
and len(result.index) > 0
)

if needs_offset:
# error: Cannot determine type of 'loffset'
result.index = result.index + self.loffset # type: ignore[has-type]

self.loffset = None
return result

def _get_resampler_for_grouping(self, groupby, key=None):
"""
Return the correct class for resampling with groupby.
Expand Down Expand Up @@ -1295,7 +1262,6 @@ def _downsample(self, how, **kwargs):
# we want to call the actual grouper method here
result = obj.groupby(self.grouper, axis=self.axis).aggregate(how, **kwargs)

result = self._apply_loffset(result)
return self._wrap_result(result)

def _adjust_binner_for_upsample(self, binner):
Expand Down Expand Up @@ -1353,7 +1319,6 @@ def _upsample(self, method, limit=None, fill_value=None):
res_index, method=method, limit=limit, fill_value=fill_value
)

result = self._apply_loffset(result)
return self._wrap_result(result)

def _wrap_result(self, result):
Expand Down Expand Up @@ -1398,11 +1363,6 @@ def _convert_obj(self, obj: NDFrameT) -> NDFrameT:
)
raise NotImplementedError(msg)

if self.loffset is not None:
# Cannot apply loffset/timedelta to PeriodIndex -> convert to
# timestamps
self.kind = "timestamp"

# convert to timestamp
if self.kind == "timestamp":
obj = obj.to_timestamp(how=self.convention)
Expand Down Expand Up @@ -1563,7 +1523,6 @@ class TimeGrouper(Grouper):
"closed",
"label",
"how",
"loffset",
"kind",
"convention",
"origin",
Expand All @@ -1581,10 +1540,8 @@ def __init__(
axis: Axis = 0,
fill_method=None,
limit=None,
loffset=None,
kind: str | None = None,
convention: Literal["start", "end", "e", "s"] | None = None,
base: int | None = None,
origin: Literal["epoch", "start", "start_day", "end", "end_day"]
| TimestampConvertibleTypes = "start_day",
offset: TimedeltaConvertibleTypes | None = None,
Expand Down Expand Up @@ -1664,22 +1621,6 @@ def __init__(
# always sort time groupers
kwargs["sort"] = True

# Handle deprecated arguments since v1.1.0 of `base` and `loffset` (GH #31809)
if base is not None and offset is not None:
raise ValueError("'offset' and 'base' cannot be present at the same time")

if base and isinstance(freq, Tick):
# this conversion handle the default behavior of base and the
# special case of GH #10530. Indeed in case when dealing with
# a TimedeltaIndex base was treated as a 'pure' offset even though
# the default behavior of base was equivalent of a modulo on
# freq_nanos.
self.offset = Timedelta(base * freq.nanos // freq.n)

if isinstance(loffset, str):
loffset = to_offset(loffset)
self.loffset = loffset

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

def _get_resampler(self, obj, kind=None):
Expand Down Expand Up @@ -1840,9 +1781,6 @@ def _get_time_delta_bins(self, ax: TimedeltaIndex):
if self.offset:
# GH 10530 & 31809
labels += self.offset
if self.loffset:
# GH 33498
labels += self.loffset

return binner, bins, labels

Expand Down
4 changes: 0 additions & 4 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -5809,8 +5809,6 @@ def resample(
label: str | None = None,
convention: str = "start",
kind: str | None = None,
loffset=None,
base: int | None = None,
on: Level = None,
level: Level = None,
origin: str | TimestampConvertibleTypes = "start_day",
Expand All @@ -5824,8 +5822,6 @@ def resample(
label=label,
convention=convention,
kind=kind,
loffset=loffset,
base=base,
on=on,
level=level,
origin=origin,
Expand Down
Loading