Skip to content

Commit 9616d84

Browse files
vamsi-verma-snoatamir
authored andcommitted
DEP: remove deprecated loffset and base args for resample and Grouper (pandas-dev#49101)
* pylint: disable access-member-before-definition for loffset * remove deprecated loffset and base args * fix docstring for resample * change date_range import to avoid flake8 warning * fix resample test_depecerated imports * move change note to deprecation section * remove all deprecated tests for resample
1 parent 9183948 commit 9616d84

File tree

8 files changed

+1
-462
lines changed

8 files changed

+1
-462
lines changed

doc/source/whatsnew/v2.0.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ Removal of prior version deprecations/changes
273273
- 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`)
274274
- Changed the behavior of :class:`Series` constructor, it will no longer infer a datetime64 or timedelta64 dtype from string entries (:issue:`41731`)
275275
- Changed behavior of :class:`Index` constructor when passed a ``SparseArray`` or ``SparseDtype`` to retain that dtype instead of casting to ``numpy.ndarray`` (:issue:`43930`)
276+
- 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`)
276277
- 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`)
277278
-
278279

pandas/core/frame.py

-4
Original file line numberDiff line numberDiff line change
@@ -11336,8 +11336,6 @@ def resample(
1133611336
label: str | None = None,
1133711337
convention: str = "start",
1133811338
kind: str | None = None,
11339-
loffset=None,
11340-
base: int | None = None,
1134111339
on: Level = None,
1134211340
level: Level = None,
1134311341
origin: str | TimestampConvertibleTypes = "start_day",
@@ -11351,8 +11349,6 @@ def resample(
1135111349
label=label,
1135211350
convention=convention,
1135311351
kind=kind,
11354-
loffset=loffset,
11355-
base=base,
1135611352
on=on,
1135711353
level=level,
1135811354
origin=origin,

pandas/core/generic.py

-43
Original file line numberDiff line numberDiff line change
@@ -8454,8 +8454,6 @@ def resample(
84548454
label: str | None = None,
84558455
convention: str = "start",
84568456
kind: str | None = None,
8457-
loffset=None,
8458-
base: int | None = None,
84598457
on: Level = None,
84608458
level: Level = None,
84618459
origin: str | TimestampConvertibleTypes = "start_day",
@@ -8493,20 +8491,6 @@ def resample(
84938491
Pass 'timestamp' to convert the resulting index to a
84948492
`DateTimeIndex` or 'period' to convert it to a `PeriodIndex`.
84958493
By default the input representation is retained.
8496-
loffset : timedelta, default None
8497-
Adjust the resampled time labels.
8498-
8499-
.. deprecated:: 1.1.0
8500-
You should add the loffset to the `df.index` after the resample.
8501-
See below.
8502-
8503-
base : int, default 0
8504-
For frequencies that evenly subdivide 1 day, the "origin" of the
8505-
aggregated intervals. For example, for '5min' frequency, base could
8506-
range from 0 through 4. Defaults to 0.
8507-
8508-
.. deprecated:: 1.1.0
8509-
The new arguments that you should use are 'offset' or 'origin'.
85108494
85118495
on : str, optional
85128496
For a DataFrame, column to use instead of index for resampling.
@@ -8842,31 +8826,6 @@ def resample(
88428826
2000-10-02 00:12:00 45
88438827
2000-10-02 00:29:00 45
88448828
Freq: 17T, dtype: int64
8845-
8846-
To replace the use of the deprecated `base` argument, you can now use `offset`,
8847-
in this example it is equivalent to have `base=2`:
8848-
8849-
>>> ts.resample('17min', offset='2min').sum()
8850-
2000-10-01 23:16:00 0
8851-
2000-10-01 23:33:00 9
8852-
2000-10-01 23:50:00 36
8853-
2000-10-02 00:07:00 39
8854-
2000-10-02 00:24:00 24
8855-
Freq: 17T, dtype: int64
8856-
8857-
To replace the use of the deprecated `loffset` argument:
8858-
8859-
>>> from pandas.tseries.frequencies import to_offset
8860-
>>> loffset = '19min'
8861-
>>> ts_out = ts.resample('17min').sum()
8862-
>>> ts_out.index = ts_out.index + to_offset(loffset)
8863-
>>> ts_out
8864-
2000-10-01 23:33:00 0
8865-
2000-10-01 23:50:00 9
8866-
2000-10-02 00:07:00 21
8867-
2000-10-02 00:24:00 54
8868-
2000-10-02 00:41:00 24
8869-
Freq: 17T, dtype: int64
88708829
"""
88718830
from pandas.core.resample import get_resampler
88728831

@@ -8878,9 +8837,7 @@ def resample(
88788837
closed=closed,
88798838
axis=axis,
88808839
kind=kind,
8881-
loffset=loffset,
88828840
convention=convention,
8883-
base=base,
88848841
key=on,
88858842
level=level,
88868843
origin=origin,

pandas/core/groupby/grouper.py

-68
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
Iterator,
1212
final,
1313
)
14-
import warnings
1514

1615
import numpy as np
1716

@@ -23,7 +22,6 @@
2322
)
2423
from pandas.errors import InvalidIndexError
2524
from pandas.util._decorators import cache_readonly
26-
from pandas.util._exceptions import find_stack_level
2725

2826
from pandas.core.dtypes.common import (
2927
is_categorical_dtype,
@@ -86,23 +84,6 @@ class Grouper:
8684
Only when `freq` parameter is passed.
8785
convention : {'start', 'end', 'e', 's'}
8886
If grouper is PeriodIndex and `freq` parameter is passed.
89-
base : int, default 0
90-
Only when `freq` parameter is passed.
91-
For frequencies that evenly subdivide 1 day, the "origin" of the
92-
aggregated intervals. For example, for '5min' frequency, base could
93-
range from 0 through 4. Defaults to 0.
94-
95-
.. deprecated:: 1.1.0
96-
The new arguments that you should use are 'offset' or 'origin'.
97-
98-
loffset : str, DateOffset, timedelta object
99-
Only when `freq` parameter is passed.
100-
101-
.. deprecated:: 1.1.0
102-
loffset is only working for ``.resample(...)`` and not for
103-
Grouper (:issue:`28302`).
104-
However, loffset is also deprecated for ``.resample(...)``
105-
See: :class:`DataFrame.resample`
10687
10788
origin : Timestamp or str, default 'start_day'
10889
The timestamp on which to adjust the grouping. The timezone of origin must
@@ -266,7 +247,6 @@ def __new__(cls, *args, **kwargs):
266247
if kwargs.get("freq") is not None:
267248
from pandas.core.resample import TimeGrouper
268249

269-
_check_deprecated_resample_kwargs(kwargs, origin=cls)
270250
cls = TimeGrouper
271251
return super().__new__(cls)
272252

@@ -954,51 +934,3 @@ def _convert_grouper(axis: Index, grouper):
954934
return grouper
955935
else:
956936
return grouper
957-
958-
959-
def _check_deprecated_resample_kwargs(kwargs, origin) -> None:
960-
"""
961-
Check for use of deprecated parameters in ``resample`` and related functions.
962-
963-
Raises the appropriate warnings if these parameters are detected.
964-
Only sets an approximate ``stacklevel`` for the warnings (see #37603, #36629).
965-
966-
Parameters
967-
----------
968-
kwargs : dict
969-
Dictionary of keyword arguments to check for deprecated parameters.
970-
origin : object
971-
From where this function is being called; either Grouper or TimeGrouper. Used
972-
to determine an approximate stacklevel.
973-
"""
974-
# Deprecation warning of `base` and `loffset` since v1.1.0:
975-
# we are raising the warning here to be able to set the `stacklevel`
976-
# properly since we need to raise the `base` and `loffset` deprecation
977-
# warning from three different cases:
978-
# core/generic.py::NDFrame.resample
979-
# core/groupby/groupby.py::GroupBy.resample
980-
# core/groupby/grouper.py::Grouper
981-
# raising these warnings from TimeGrouper directly would fail the test:
982-
# tests/resample/test_deprecated.py::test_deprecating_on_loffset_and_base
983-
984-
if kwargs.get("base", None) is not None:
985-
warnings.warn(
986-
"'base' in .resample() and in Grouper() is deprecated.\n"
987-
"The new arguments that you should use are 'offset' or 'origin'.\n"
988-
'\n>>> df.resample(freq="3s", base=2)\n'
989-
"\nbecomes:\n"
990-
'\n>>> df.resample(freq="3s", offset="2s")\n',
991-
FutureWarning,
992-
stacklevel=find_stack_level(),
993-
)
994-
if kwargs.get("loffset", None) is not None:
995-
warnings.warn(
996-
"'loffset' in .resample() and in Grouper() is deprecated.\n"
997-
'\n>>> df.resample(freq="3s", loffset="8H")\n'
998-
"\nbecomes:\n"
999-
"\n>>> from pandas.tseries.frequencies import to_offset"
1000-
'\n>>> df = df.resample(freq="3s").mean()'
1001-
'\n>>> df.index = df.index.to_timestamp() + to_offset("8H")\n',
1002-
FutureWarning,
1003-
stacklevel=find_stack_level(),
1004-
)

pandas/core/resample.py

-62
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@
8989
is_superperiod,
9090
)
9191
from pandas.tseries.offsets import (
92-
DateOffset,
9392
Day,
9493
Nano,
9594
Tick,
@@ -139,7 +138,6 @@ class Resampler(BaseGroupBy, PandasObject):
139138
"closed",
140139
"label",
141140
"convention",
142-
"loffset",
143141
"kind",
144142
"origin",
145143
"offset",
@@ -358,7 +356,6 @@ def aggregate(self, func=None, *args, **kwargs):
358356
how = func
359357
result = self._groupby_and_aggregate(how, *args, **kwargs)
360358

361-
result = self._apply_loffset(result)
362359
return result
363360

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

478-
result = self._apply_loffset(result)
479475
return self._wrap_result(result)
480476

481-
def _apply_loffset(self, result):
482-
"""
483-
If loffset is set, offset the result index.
484-
485-
This is NOT an idempotent routine, it will be applied
486-
exactly once to the result.
487-
488-
Parameters
489-
----------
490-
result : Series or DataFrame
491-
the result of resample
492-
"""
493-
# error: Cannot determine type of 'loffset'
494-
needs_offset = (
495-
isinstance(
496-
self.loffset, # type: ignore[has-type]
497-
(DateOffset, timedelta, np.timedelta64),
498-
)
499-
and isinstance(result.index, DatetimeIndex)
500-
and len(result.index) > 0
501-
)
502-
503-
if needs_offset:
504-
# error: Cannot determine type of 'loffset'
505-
result.index = result.index + self.loffset # type: ignore[has-type]
506-
507-
self.loffset = None
508-
return result
509-
510477
def _get_resampler_for_grouping(self, groupby, key=None):
511478
"""
512479
Return the correct class for resampling with groupby.
@@ -1295,7 +1262,6 @@ def _downsample(self, how, **kwargs):
12951262
# we want to call the actual grouper method here
12961263
result = obj.groupby(self.grouper, axis=self.axis).aggregate(how, **kwargs)
12971264

1298-
result = self._apply_loffset(result)
12991265
return self._wrap_result(result)
13001266

13011267
def _adjust_binner_for_upsample(self, binner):
@@ -1353,7 +1319,6 @@ def _upsample(self, method, limit=None, fill_value=None):
13531319
res_index, method=method, limit=limit, fill_value=fill_value
13541320
)
13551321

1356-
result = self._apply_loffset(result)
13571322
return self._wrap_result(result)
13581323

13591324
def _wrap_result(self, result):
@@ -1398,11 +1363,6 @@ def _convert_obj(self, obj: NDFrameT) -> NDFrameT:
13981363
)
13991364
raise NotImplementedError(msg)
14001365

1401-
if self.loffset is not None:
1402-
# Cannot apply loffset/timedelta to PeriodIndex -> convert to
1403-
# timestamps
1404-
self.kind = "timestamp"
1405-
14061366
# convert to timestamp
14071367
if self.kind == "timestamp":
14081368
obj = obj.to_timestamp(how=self.convention)
@@ -1563,7 +1523,6 @@ class TimeGrouper(Grouper):
15631523
"closed",
15641524
"label",
15651525
"how",
1566-
"loffset",
15671526
"kind",
15681527
"convention",
15691528
"origin",
@@ -1581,10 +1540,8 @@ def __init__(
15811540
axis: Axis = 0,
15821541
fill_method=None,
15831542
limit=None,
1584-
loffset=None,
15851543
kind: str | None = None,
15861544
convention: Literal["start", "end", "e", "s"] | None = None,
1587-
base: int | None = None,
15881545
origin: Literal["epoch", "start", "start_day", "end", "end_day"]
15891546
| TimestampConvertibleTypes = "start_day",
15901547
offset: TimedeltaConvertibleTypes | None = None,
@@ -1664,22 +1621,6 @@ def __init__(
16641621
# always sort time groupers
16651622
kwargs["sort"] = True
16661623

1667-
# Handle deprecated arguments since v1.1.0 of `base` and `loffset` (GH #31809)
1668-
if base is not None and offset is not None:
1669-
raise ValueError("'offset' and 'base' cannot be present at the same time")
1670-
1671-
if base and isinstance(freq, Tick):
1672-
# this conversion handle the default behavior of base and the
1673-
# special case of GH #10530. Indeed in case when dealing with
1674-
# a TimedeltaIndex base was treated as a 'pure' offset even though
1675-
# the default behavior of base was equivalent of a modulo on
1676-
# freq_nanos.
1677-
self.offset = Timedelta(base * freq.nanos // freq.n)
1678-
1679-
if isinstance(loffset, str):
1680-
loffset = to_offset(loffset)
1681-
self.loffset = loffset
1682-
16831624
super().__init__(freq=freq, axis=axis, **kwargs)
16841625

16851626
def _get_resampler(self, obj, kind=None):
@@ -1840,9 +1781,6 @@ def _get_time_delta_bins(self, ax: TimedeltaIndex):
18401781
if self.offset:
18411782
# GH 10530 & 31809
18421783
labels += self.offset
1843-
if self.loffset:
1844-
# GH 33498
1845-
labels += self.loffset
18461784

18471785
return binner, bins, labels
18481786

pandas/core/series.py

-4
Original file line numberDiff line numberDiff line change
@@ -5809,8 +5809,6 @@ def resample(
58095809
label: str | None = None,
58105810
convention: str = "start",
58115811
kind: str | None = None,
5812-
loffset=None,
5813-
base: int | None = None,
58145812
on: Level = None,
58155813
level: Level = None,
58165814
origin: str | TimestampConvertibleTypes = "start_day",
@@ -5824,8 +5822,6 @@ def resample(
58245822
label=label,
58255823
convention=convention,
58265824
kind=kind,
5827-
loffset=loffset,
5828-
base=base,
58295825
on=on,
58305826
level=level,
58315827
origin=origin,

0 commit comments

Comments
 (0)