From d962f70b76094f2d264049ac41d399b8f55571ad Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sat, 7 Dec 2019 23:59:29 -0800 Subject: [PATCH 1/5] DEPR: Remove how, fill_method, and limit from resample --- doc/source/whatsnew/v1.0.0.rst | 1 + pandas/core/generic.py | 26 +--------- pandas/core/resample.py | 55 +--------------------- pandas/tests/resample/test_base.py | 29 +++++------- pandas/tests/resample/test_period_index.py | 3 -- pandas/tests/resample/test_resample_api.py | 48 +++++++++++++++++-- 6 files changed, 59 insertions(+), 103 deletions(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 7fe7970199b5e..cddfa7cd9fb18 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -598,6 +598,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:``) - 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`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 3e41721b65f5d..fcd160ed8d9a7 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -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, @@ -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()`` 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(...).()``, - 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', @@ -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 @@ -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, @@ -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): """ diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 58c4a97d651d8..77c42efb78969 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -953,58 +953,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()" - - # 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. @@ -1342,8 +1290,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): diff --git a/pandas/tests/resample/test_base.py b/pandas/tests/resample/test_base.py index 622b85f2a398c..02203f476af8e 100644 --- a/pandas/tests/resample/test_base.py +++ b/pandas/tests/resample/test_base.py @@ -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)] @@ -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 diff --git a/pandas/tests/resample/test_period_index.py b/pandas/tests/resample/test_period_index.py index 219491367d292..0ed0bf18a82ee 100644 --- a/pandas/tests/resample/test_period_index.py +++ b/pandas/tests/resample/test_period_index.py @@ -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"]) diff --git a/pandas/tests/resample/test_resample_api.py b/pandas/tests/resample/test_resample_api.py index 8e1774d8ee5b7..7852afcdbfea9 100644 --- a/pandas/tests/resample/test_resample_api.py +++ b/pandas/tests/resample/test_resample_api.py @@ -179,7 +179,7 @@ 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 @@ -187,9 +187,49 @@ def test_combined_up_downsampling_of_irregular(): 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) From 1e03089326331f846fde2e64c0a63a937d1870a8 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 8 Dec 2019 00:02:11 -0800 Subject: [PATCH 2/5] Add issue number from pr --- doc/source/whatsnew/v1.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index cddfa7cd9fb18..b346d09495442 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -598,7 +598,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:``) +- 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`) From 6525a81a360734ccb4d2913df5b3ac8a40dc9098 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 8 Dec 2019 14:34:09 -0800 Subject: [PATCH 3/5] Add -v to flake8 --- ci/code_checks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index cfe55f1e05f71..dbc4f6bbd7d7a 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -58,7 +58,7 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then # `setup.cfg` contains the list of error codes that are being ignored in flake8 echo "flake8 --version" - flake8 --version + flake8 --version -v # pandas/_libs/src is C code, so no need to search there. MSG='Linting .py code' ; echo $MSG From 0c2278978538100c7172972ac2e9a7d07182feb7 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 8 Dec 2019 20:08:21 -0800 Subject: [PATCH 4/5] Remove unused import --- pandas/core/resample.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 77c42efb78969..67f06ea7bea6a 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -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 From 5b07a3245e0a7badd470f29cff5f1e000335c0b8 Mon Sep 17 00:00:00 2001 From: Matt Roeschke Date: Sun, 8 Dec 2019 20:08:56 -0800 Subject: [PATCH 5/5] remove -v --- ci/code_checks.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index dbc4f6bbd7d7a..cfe55f1e05f71 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -58,7 +58,7 @@ if [[ -z "$CHECK" || "$CHECK" == "lint" ]]; then # `setup.cfg` contains the list of error codes that are being ignored in flake8 echo "flake8 --version" - flake8 --version -v + flake8 --version # pandas/_libs/src is C code, so no need to search there. MSG='Linting .py code' ; echo $MSG