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

DEPR: Remove how, fill_method, and limit from resample #30139

Merged
merged 6 commits into from
Dec 9, 2019
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/v1.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,7 @@ or ``matplotlib.Axes.plot``. See :ref:`plotting.formatters` for more.
- In :func:`concat` the default value for ``sort`` has been changed from ``None`` to ``False`` (:issue:`20613`)
- Removed previously deprecated "raise_conflict" argument from :meth:`DataFrame.update`, use "errors" instead (:issue:`23585`)
- Removed previously deprecated keyword "n" from :meth:`DatetimeIndex.shift`, :meth:`TimedeltaIndex.shift`, :meth:`PeriodIndex.shift`, use "periods" instead (:issue:`22458`)
- Removed previously deprecated keywords ``how``, ``fill_method``, and ``limit`` from :meth:`DataFrame.resample` (:issue:`30139`)
- Passing an integer to :meth:`Series.fillna` or :meth:`DataFrame.fillna` with ``timedelta64[ns]`` dtype now raises ``TypeError`` (:issue:`24694`)
- Passing multiple axes to :meth:`DataFrame.dropna` is no longer supported (:issue:`20995`)
- Removed previously deprecated :meth:`Series.nonzero`, use `to_numpy().nonzero()` instead (:issue:`24048`)
Expand Down
26 changes: 2 additions & 24 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -7728,15 +7728,12 @@ def between_time(
def resample(
self,
rule,
how: Optional[str] = None,
axis=0,
fill_method: Optional[str] = None,
closed: Optional[str] = None,
label: Optional[str] = None,
convention: str = "start",
kind: Optional[str] = None,
loffset=None,
limit: Optional[int] = None,
base: int = 0,
on=None,
level=None,
Expand All @@ -7753,22 +7750,10 @@ def resample(
----------
rule : DateOffset, Timedelta or str
The offset string or object representing target conversion.
how : str
Method for down/re-sampling, default to 'mean' for downsampling.

.. deprecated:: 0.18.0
The new syntax is ``.resample(...).mean()``, or
``.resample(...).apply(<func>)``
axis : {0 or 'index', 1 or 'columns'}, default 0
Which axis to use for up- or down-sampling. For `Series` this
will default to 0, i.e. along the rows. Must be
`DatetimeIndex`, `TimedeltaIndex` or `PeriodIndex`.
fill_method : str, default None
Filling method for upsampling.

.. deprecated:: 0.18.0
The new syntax is ``.resample(...).<func>()``,
e.g. ``.resample(...).pad()``
closed : {'right', 'left'}, default None
Which side of bin interval is closed. The default is 'left'
for all frequency offsets except for 'M', 'A', 'Q', 'BM',
Expand All @@ -7786,10 +7771,6 @@ def resample(
By default the input representation is retained.
loffset : timedelta, default None
Adjust the resampled time labels.
limit : int, default None
Maximum size gap when reindexing with `fill_method`.

.. deprecated:: 0.18.0
base : int, default 0
For frequencies that evenly subdivide 1 day, the "origin" of the
aggregated intervals. For example, for '5min' frequency, base could
Expand Down Expand Up @@ -8021,10 +8002,10 @@ def resample(
2000-01-04 36 90
"""

from pandas.core.resample import resample, _maybe_process_deprecations
from pandas.core.resample import resample

axis = self._get_axis_number(axis)
r = resample(
return resample(
self,
freq=rule,
label=label,
Expand All @@ -8037,9 +8018,6 @@ def resample(
key=on,
level=level,
)
return _maybe_process_deprecations(
r, how=how, fill_method=fill_method, limit=limit
)

def first(self, offset):
"""
Expand Down
56 changes: 1 addition & 55 deletions pandas/core/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from datetime import timedelta
from textwrap import dedent
from typing import Dict, no_type_check
import warnings

import numpy as np

Expand Down Expand Up @@ -953,58 +952,6 @@ def h(self, _method=method):
setattr(Resampler, method, h)


def _maybe_process_deprecations(r, how=None, fill_method=None, limit=None):
"""
Potentially we might have a deprecation warning, show it
but call the appropriate methods anyhow.
"""

if how is not None:

# .resample(..., how='sum')
if isinstance(how, str):
method = "{0}()".format(how)

# .resample(..., how=lambda x: ....)
else:
method = ".apply(<func>)"

# if we have both a how and fill_method, then show
# the following warning
if fill_method is None:
warnings.warn(
"how in .resample() is deprecated\n"
"the new syntax is "
".resample(...).{method}".format(method=method),
FutureWarning,
stacklevel=3,
)
r = r.aggregate(how)

if fill_method is not None:

# show the prior function call
method = "." + method if how is not None else ""

args = "limit={0}".format(limit) if limit is not None else ""
warnings.warn(
"fill_method is deprecated to .resample()\n"
"the new syntax is .resample(...){method}"
".{fill_method}({args})".format(
method=method, fill_method=fill_method, args=args
),
FutureWarning,
stacklevel=3,
)

if how is not None:
r = getattr(r, fill_method)(limit=limit)
else:
r = r.aggregate(fill_method, limit=limit)

return r


class _GroupByMixin(GroupByMixin):
"""
Provide the groupby facilities.
Expand Down Expand Up @@ -1342,8 +1289,7 @@ def get_resampler_for_grouping(

tg = TimeGrouper(freq=rule, **kwargs)
resampler = tg._get_resampler(groupby.obj, kind=kind)
r = resampler._get_resampler_for_grouping(groupby=groupby)
return _maybe_process_deprecations(r, how=how, fill_method=fill_method, limit=limit)
return resampler._get_resampler_for_grouping(groupby=groupby)


class TimeGrouper(Grouper):
Expand Down
29 changes: 11 additions & 18 deletions pandas/tests/resample/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ def test_resample_empty_dtypes(index, dtype, resample_method):


@all_ts
def test_resample_loffset_arg_type(frame, create_index):
@pytest.mark.parametrize("arg", ["mean", {"value": "mean"}, ["mean"]])
def test_resample_loffset_arg_type(frame, create_index, arg):
# GH 13218, 15002
df = frame
expected_means = [df.values[i : i + 2].mean() for i in range(0, len(df.values), 2)]
Expand All @@ -220,26 +221,18 @@ def test_resample_loffset_arg_type(frame, create_index):
expected_index += timedelta(hours=2)
expected = DataFrame({"value": expected_means}, index=expected_index)

for arg in ["mean", {"value": "mean"}, ["mean"]]:
result_agg = df.resample("2D", loffset="2H").agg(arg)

result_agg = df.resample("2D", loffset="2H").agg(arg)
if isinstance(arg, list):
expected.columns = pd.MultiIndex.from_tuples([("value", "mean")])

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
result_how = df.resample("2D", how=arg, loffset="2H")

if isinstance(arg, list):
expected.columns = pd.MultiIndex.from_tuples([("value", "mean")])

# GH 13022, 7687 - TODO: fix resample w/ TimedeltaIndex
if isinstance(expected.index, TimedeltaIndex):
msg = "DataFrame are different"
with pytest.raises(AssertionError, match=msg):
tm.assert_frame_equal(result_agg, expected)
with pytest.raises(AssertionError, match=msg):
tm.assert_frame_equal(result_how, expected)
else:
# GH 13022, 7687 - TODO: fix resample w/ TimedeltaIndex
if isinstance(expected.index, TimedeltaIndex):
msg = "DataFrame are different"
with pytest.raises(AssertionError, match=msg):
tm.assert_frame_equal(result_agg, expected)
tm.assert_frame_equal(result_how, expected)
else:
tm.assert_frame_equal(result_agg, expected)


@all_ts
Expand Down
3 changes: 0 additions & 3 deletions pandas/tests/resample/test_period_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,12 +732,9 @@ def test_loffset_returns_datetimeindex(self, frame, kind, agg_arg):
expected = DataFrame({"value": expected_means}, index=expected_index)

result_agg = df.resample("2D", loffset="2H", kind=kind).agg(agg_arg)
with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
result_how = df.resample("2D", how=agg_arg, loffset="2H", kind=kind)
if isinstance(agg_arg, list):
expected.columns = pd.MultiIndex.from_tuples([("value", "mean")])
tm.assert_frame_equal(result_agg, expected)
tm.assert_frame_equal(result_how, expected)

@pytest.mark.parametrize("freq, period_mult", [("H", 24), ("12H", 2)])
@pytest.mark.parametrize("kind", [None, "period"])
Expand Down
48 changes: 44 additions & 4 deletions pandas/tests/resample/test_resample_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,57 @@ def test_downsample_but_actually_upsampling():

def test_combined_up_downsampling_of_irregular():

# since we are reallydoing an operation like this
# since we are really doing an operation like this
# ts2.resample('2s').mean().ffill()
# preserve these semantics

rng = pd.date_range("1/1/2012", periods=100, freq="S")
ts = Series(np.arange(len(rng)), index=rng)
ts2 = ts.iloc[[0, 1, 2, 3, 5, 7, 11, 15, 16, 25, 30]]

with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
result = ts2.resample("2s", how="mean", fill_method="ffill")
expected = ts2.resample("2s").mean().ffill()
result = ts2.resample("2s").mean().ffill()
expected = Series(
[
0.5,
2.5,
5.0,
7.0,
7.0,
11.0,
11.0,
15.0,
16.0,
16.0,
16.0,
16.0,
25.0,
25.0,
25.0,
30.0,
],
index=pd.DatetimeIndex(
[
"2012-01-01 00:00:00",
"2012-01-01 00:00:02",
"2012-01-01 00:00:04",
"2012-01-01 00:00:06",
"2012-01-01 00:00:08",
"2012-01-01 00:00:10",
"2012-01-01 00:00:12",
"2012-01-01 00:00:14",
"2012-01-01 00:00:16",
"2012-01-01 00:00:18",
"2012-01-01 00:00:20",
"2012-01-01 00:00:22",
"2012-01-01 00:00:24",
"2012-01-01 00:00:26",
"2012-01-01 00:00:28",
"2012-01-01 00:00:30",
],
dtype="datetime64[ns]",
freq="2S",
),
)
tm.assert_series_equal(result, expected)


Expand Down