From 84b0176771c8d45a8a2c5279309444d69c494527 Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 5 Mar 2024 21:35:04 -0500 Subject: [PATCH 1/3] CLN: Enforce deprecation of method and limit in pct_change methods --- doc/source/whatsnew/v3.0.0.rst | 1 + pandas/core/generic.py | 56 ++------- pandas/core/groupby/groupby.py | 50 ++------ pandas/tests/frame/methods/test_pct_change.py | 119 +++++------------- pandas/tests/groupby/test_groupby_dropna.py | 15 +-- .../tests/groupby/transform/test_transform.py | 56 +-------- 6 files changed, 56 insertions(+), 241 deletions(-) diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index fae7edba057ec..26d300680a34d 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -226,6 +226,7 @@ Removal of prior version deprecations/changes - Removed ``read_gbq`` and ``DataFrame.to_gbq``. Use ``pandas_gbq.read_gbq`` and ``pandas_gbq.to_gbq`` instead https://pandas-gbq.readthedocs.io/en/latest/api.html (:issue:`55525`) - Removed ``use_nullable_dtypes`` from :func:`read_parquet` (:issue:`51853`) - Removed ``year``, ``month``, ``quarter``, ``day``, ``hour``, ``minute``, and ``second`` keywords in the :class:`PeriodIndex` constructor, use :meth:`PeriodIndex.from_fields` instead (:issue:`55960`) +- Removed argument ``limit`` from :meth:`DataFrame.pct_change`, :meth:`Series.pct_change`, :meth:`.DataFrameGroupBy.pct_change`, and :meth:`.SeriesGroupBy.pct_change`; the argument ``method`` must be set to ``None`` and will be removed in a future version of pandas (:issue:`53520`) - Removed deprecated argument ``obj`` in :meth:`.DataFrameGroupBy.get_group` and :meth:`.SeriesGroupBy.get_group` (:issue:`53545`) - Removed deprecated behavior of :meth:`Series.agg` using :meth:`Series.apply` (:issue:`53325`) - Removed option ``mode.use_inf_as_na``, convert inf entries to ``NaN`` before instead (:issue:`51684`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 1bc6b7a3eea03..68578098ca609 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -11120,8 +11120,7 @@ def describe( def pct_change( self, periods: int = 1, - fill_method: FillnaOptions | None | lib.NoDefault = lib.no_default, - limit: int | None | lib.NoDefault = lib.no_default, + fill_method: None = None, freq=None, **kwargs, ) -> Self: @@ -11143,17 +11142,12 @@ def pct_change( ---------- periods : int, default 1 Periods to shift for forming percent change. - fill_method : {'backfill', 'bfill', 'pad', 'ffill', None}, default 'pad' - How to handle NAs **before** computing percent changes. + fill_method : None + Must be None. This argument will be removed in a future version of pandas. .. deprecated:: 2.1 All options of `fill_method` are deprecated except `fill_method=None`. - limit : int, default None - The number of consecutive NAs to fill before stopping. - - .. deprecated:: 2.1 - freq : DateOffset, timedelta, or str, optional Increment to use from time series API (e.g. 'ME' or BDay()). **kwargs @@ -11260,52 +11254,18 @@ def pct_change( APPL -0.252395 -0.011860 NaN """ # GH#53491 - if fill_method not in (lib.no_default, None) or limit is not lib.no_default: - warnings.warn( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - f"{type(self).__name__}.pct_change are deprecated and will be removed " - "in a future version. Either fill in any non-leading NA values prior " - "to calling pct_change or specify 'fill_method=None' to not fill NA " - "values.", - FutureWarning, - stacklevel=find_stack_level(), - ) - if fill_method is lib.no_default: - if limit is lib.no_default: - cols = self.items() if self.ndim == 2 else [(None, self)] - for _, col in cols: - if len(col) > 0: - mask = col.isna().values - mask = mask[np.argmax(~mask) :] - if mask.any(): - warnings.warn( - "The default fill_method='pad' in " - f"{type(self).__name__}.pct_change is deprecated and " - "will be removed in a future version. Either fill in " - "any non-leading NA values prior to calling pct_change " - "or specify 'fill_method=None' to not fill NA values.", - FutureWarning, - stacklevel=find_stack_level(), - ) - break - fill_method = "pad" - if limit is lib.no_default: - limit = None + if fill_method is not None: + raise ValueError(f"fill_method must be None; got {fill_method=}.") axis = self._get_axis_number(kwargs.pop("axis", "index")) - if fill_method is None: - data = self - else: - data = self._pad_or_backfill(fill_method, axis=axis, limit=limit) - - shifted = data.shift(periods=periods, freq=freq, axis=axis, **kwargs) + shifted = self.shift(periods=periods, freq=freq, axis=axis, **kwargs) # Unsupported left operand type for / ("Self") - rs = data / shifted - 1 # type: ignore[operator] + rs = self / shifted - 1 # type: ignore[operator] if freq is not None: # Shift method is implemented differently when freq is not None # We want to restore the original index rs = rs.loc[~rs.index.duplicated()] - rs = rs.reindex_like(data) + rs = rs.reindex_like(self) return rs.__finalize__(self, method="pct_change") @final diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 61168f71f4924..e77adb5620522 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -45,7 +45,6 @@ class providing the base-class of operations. AnyArrayLike, ArrayLike, DtypeObj, - FillnaOptions, IndexLabel, IntervalClosedType, NDFrameT, @@ -5147,8 +5146,7 @@ def diff( def pct_change( self, periods: int = 1, - fill_method: FillnaOptions | None | lib.NoDefault = lib.no_default, - limit: int | None | lib.NoDefault = lib.no_default, + fill_method: None = None, freq=None, ): """ @@ -5161,19 +5159,11 @@ def pct_change( a period of 1 means adjacent elements are compared, whereas a period of 2 compares every other element. - fill_method : FillnaOptions or None, default None - Specifies how to handle missing values after the initial shift - operation necessary for percentage change calculation. Users are - encouraged to handle missing values manually in future versions. - Valid options are: - - A FillnaOptions value ('ffill', 'bfill') for forward or backward filling. - - None to avoid filling. - Note: Usage is discouraged due to impending deprecation. + fill_method : None + Must be None. This argument will be removed in a future version of pandas. - limit : int or None, default None - The maximum number of consecutive NA values to fill, based on the chosen - `fill_method`. Address NaN values prior to using `pct_change` as this - parameter is nearing deprecation. + .. deprecated:: 2.1 + All options of `fill_method` are deprecated except `fill_method=None`. freq : str, pandas offset object, or None, default None The frequency increment for time series data (e.g., 'M' for month-end). @@ -5227,40 +5217,14 @@ def pct_change( goldfish 0.2 0.125 """ # GH#53491 - if fill_method not in (lib.no_default, None) or limit is not lib.no_default: - warnings.warn( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - f"{type(self).__name__}.pct_change are deprecated and will be removed " - "in a future version. Either fill in any non-leading NA values prior " - "to calling pct_change or specify 'fill_method=None' to not fill NA " - "values.", - FutureWarning, - stacklevel=find_stack_level(), - ) - if fill_method is lib.no_default: - if limit is lib.no_default and any( - grp.isna().values.any() for _, grp in self - ): - warnings.warn( - "The default fill_method='ffill' in " - f"{type(self).__name__}.pct_change is deprecated and will " - "be removed in a future version. Either fill in any " - "non-leading NA values prior to calling pct_change or " - "specify 'fill_method=None' to not fill NA values.", - FutureWarning, - stacklevel=find_stack_level(), - ) - fill_method = "ffill" - if limit is lib.no_default: - limit = None + if fill_method is not None: + raise ValueError(f"fill_method must be None; got {fill_method=}.") # TODO(GH#23918): Remove this conditional for SeriesGroupBy when # GH#23918 is fixed if freq is not None: f = lambda x: x.pct_change( periods=periods, - fill_method=fill_method, - limit=limit, freq=freq, axis=0, ) diff --git a/pandas/tests/frame/methods/test_pct_change.py b/pandas/tests/frame/methods/test_pct_change.py index 92b66e12d4356..7d4197577228e 100644 --- a/pandas/tests/frame/methods/test_pct_change.py +++ b/pandas/tests/frame/methods/test_pct_change.py @@ -10,30 +10,17 @@ class TestDataFramePctChange: @pytest.mark.parametrize( - "periods, fill_method, limit, exp", + "periods, exp", [ - (1, "ffill", None, [np.nan, np.nan, np.nan, 1, 1, 1.5, 0, 0]), - (1, "ffill", 1, [np.nan, np.nan, np.nan, 1, 1, 1.5, 0, np.nan]), - (1, "bfill", None, [np.nan, 0, 0, 1, 1, 1.5, np.nan, np.nan]), - (1, "bfill", 1, [np.nan, np.nan, 0, 1, 1, 1.5, np.nan, np.nan]), - (-1, "ffill", None, [np.nan, np.nan, -0.5, -0.5, -0.6, 0, 0, np.nan]), - (-1, "ffill", 1, [np.nan, np.nan, -0.5, -0.5, -0.6, 0, np.nan, np.nan]), - (-1, "bfill", None, [0, 0, -0.5, -0.5, -0.6, np.nan, np.nan, np.nan]), - (-1, "bfill", 1, [np.nan, 0, -0.5, -0.5, -0.6, np.nan, np.nan, np.nan]), + (1, [np.nan, np.nan, np.nan, 1, 1, 1.5, np.nan, np.nan]), + (-1, [np.nan, np.nan, -0.5, -0.5, -0.6, np.nan, np.nan, np.nan]), ], ) - def test_pct_change_with_nas( - self, periods, fill_method, limit, exp, frame_or_series - ): + def test_pct_change_with_nas(self, periods, exp, frame_or_series): vals = [np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan] obj = frame_or_series(vals) - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - f"{type(obj).__name__}.pct_change are deprecated" - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - res = obj.pct_change(periods=periods, fill_method=fill_method, limit=limit) + res = obj.pct_change(periods=periods) tm.assert_equal(res, frame_or_series(exp)) def test_pct_change_numeric(self): @@ -45,40 +32,28 @@ def test_pct_change_numeric(self): pnl.iat[1, 1] = np.nan pnl.iat[2, 3] = 60 - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "DataFrame.pct_change are deprecated" - ) - for axis in range(2): - expected = pnl.ffill(axis=axis) / pnl.ffill(axis=axis).shift(axis=axis) - 1 - - with tm.assert_produces_warning(FutureWarning, match=msg): - result = pnl.pct_change(axis=axis, fill_method="pad") + expected = pnl / pnl.shift(axis=axis) - 1 + result = pnl.pct_change(axis=axis) tm.assert_frame_equal(result, expected) def test_pct_change(self, datetime_frame): - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "DataFrame.pct_change are deprecated" - ) - - rs = datetime_frame.pct_change(fill_method=None) + rs = datetime_frame.pct_change() tm.assert_frame_equal(rs, datetime_frame / datetime_frame.shift(1) - 1) rs = datetime_frame.pct_change(2) filled = datetime_frame.ffill() tm.assert_frame_equal(rs, filled / filled.shift(2) - 1) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs = datetime_frame.pct_change(fill_method="bfill", limit=1) - filled = datetime_frame.bfill(limit=1) - tm.assert_frame_equal(rs, filled / filled.shift(1) - 1) + rs = datetime_frame.pct_change() + tm.assert_frame_equal(rs, datetime_frame / datetime_frame.shift(1) - 1) rs = datetime_frame.pct_change(freq="5D") - filled = datetime_frame.ffill() tm.assert_frame_equal( - rs, (filled / filled.shift(freq="5D") - 1).reindex_like(filled) + rs, + (datetime_frame / datetime_frame.shift(freq="5D") - 1).reindex_like( + datetime_frame + ), ) def test_pct_change_shift_over_nas(self): @@ -86,75 +61,45 @@ def test_pct_change_shift_over_nas(self): df = DataFrame({"a": s, "b": s}) - msg = "The default fill_method='pad' in DataFrame.pct_change is deprecated" - with tm.assert_produces_warning(FutureWarning, match=msg): - chg = df.pct_change() - - expected = Series([np.nan, 0.5, 0.0, 2.5 / 1.5 - 1, 0.2]) + chg = df.pct_change() + expected = Series([np.nan, 0.5, np.nan, np.nan, 0.2]) edf = DataFrame({"a": expected, "b": expected}) tm.assert_frame_equal(chg, edf) @pytest.mark.parametrize( - "freq, periods, fill_method, limit", + "freq, periods", [ - ("5B", 5, None, None), - ("3B", 3, None, None), - ("3B", 3, "bfill", None), - ("7B", 7, "pad", 1), - ("7B", 7, "bfill", 3), - ("14B", 14, None, None), + ("5B", 5), + ("3B", 3), + ("14B", 14), ], ) def test_pct_change_periods_freq( - self, datetime_frame, freq, periods, fill_method, limit + self, + datetime_frame, + freq, + periods, ): - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "DataFrame.pct_change are deprecated" - ) - # GH#7292 - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_freq = datetime_frame.pct_change( - freq=freq, fill_method=fill_method, limit=limit - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_periods = datetime_frame.pct_change( - periods, fill_method=fill_method, limit=limit - ) + rs_freq = datetime_frame.pct_change(freq=freq) + rs_periods = datetime_frame.pct_change(periods) tm.assert_frame_equal(rs_freq, rs_periods) empty_ts = DataFrame(index=datetime_frame.index, columns=datetime_frame.columns) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_freq = empty_ts.pct_change( - freq=freq, fill_method=fill_method, limit=limit - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_periods = empty_ts.pct_change( - periods, fill_method=fill_method, limit=limit - ) + rs_freq = empty_ts.pct_change(freq=freq) + rs_periods = empty_ts.pct_change(periods) tm.assert_frame_equal(rs_freq, rs_periods) -@pytest.mark.parametrize("fill_method", ["pad", "ffill", None]) -def test_pct_change_with_duplicated_indices(fill_method): +def test_pct_change_with_duplicated_indices(): # GH30463 data = DataFrame( {0: [np.nan, 1, 2, 3, 9, 18], 1: [0, 1, np.nan, 3, 9, 18]}, index=["a", "b"] * 3 ) - warn = None if fill_method is None else FutureWarning - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "DataFrame.pct_change are deprecated" - ) - with tm.assert_produces_warning(warn, match=msg): - result = data.pct_change(fill_method=fill_method) + result = data.pct_change() - if fill_method is None: - second_column = [np.nan, np.inf, np.nan, np.nan, 2.0, 1.0] - else: - second_column = [np.nan, np.inf, 0.0, 2.0, 2.0, 1.0] + second_column = [np.nan, np.inf, np.nan, np.nan, 2.0, 1.0] expected = DataFrame( {0: [np.nan, np.nan, 1.0, 0.5, 2.0, 1.0], 1: second_column}, index=["a", "b"] * 3, @@ -162,7 +107,7 @@ def test_pct_change_with_duplicated_indices(fill_method): tm.assert_frame_equal(result, expected) -def test_pct_change_none_beginning_no_warning(): +def test_pct_change_none_beginning(): # GH#54481 df = DataFrame( [ diff --git a/pandas/tests/groupby/test_groupby_dropna.py b/pandas/tests/groupby/test_groupby_dropna.py index 54efe163f077e..68030c394d606 100644 --- a/pandas/tests/groupby/test_groupby_dropna.py +++ b/pandas/tests/groupby/test_groupby_dropna.py @@ -584,14 +584,8 @@ def test_categorical_reducers(reduction_func, observed, sort, as_index, index_ki tm.assert_equal(result, expected) -def test_categorical_transformers( - request, transformation_func, observed, sort, as_index -): +def test_categorical_transformers(transformation_func, observed, sort, as_index): # GH#36327 - if transformation_func == "fillna": - msg = "GH#49651 fillna may incorrectly reorders results when dropna=False" - request.applymarker(pytest.mark.xfail(reason=msg, strict=False)) - values = np.append(np.random.default_rng(2).choice([1, 2, None], size=19), None) df = pd.DataFrame( {"x": pd.Categorical(values, categories=[1, 2, 3]), "y": range(20)} @@ -621,12 +615,7 @@ def test_categorical_transformers( ) gb_dropna = df.groupby("x", dropna=True, observed=observed, sort=sort) - msg = "The default fill_method='ffill' in DataFrameGroupBy.pct_change is deprecated" - if transformation_func == "pct_change": - with tm.assert_produces_warning(FutureWarning, match=msg): - result = getattr(gb_keepna, "pct_change")(*args) - else: - result = getattr(gb_keepna, transformation_func)(*args) + result = getattr(gb_keepna, transformation_func)(*args) expected = getattr(gb_dropna, transformation_func)(*args) for iloc, value in zip( diff --git a/pandas/tests/groupby/transform/test_transform.py b/pandas/tests/groupby/transform/test_transform.py index db327cc689afe..a5b6e19d8b065 100644 --- a/pandas/tests/groupby/transform/test_transform.py +++ b/pandas/tests/groupby/transform/test_transform.py @@ -344,31 +344,12 @@ def mock_op(x): test_op = lambda x: x.transform(transformation_func) mock_op = lambda x: getattr(x, transformation_func)() - if transformation_func == "pct_change": - msg = "The default fill_method='pad' in DataFrame.pct_change is deprecated" - groupby_msg = ( - "The default fill_method='ffill' in DataFrameGroupBy.pct_change " - "is deprecated" - ) - warn = FutureWarning - groupby_warn = FutureWarning - elif transformation_func == "fillna": - msg = "" - groupby_msg = "DataFrameGroupBy.fillna is deprecated" - warn = None - groupby_warn = FutureWarning - else: - msg = groupby_msg = "" - warn = groupby_warn = None - - with tm.assert_produces_warning(groupby_warn, match=groupby_msg): - result = test_op(df.groupby("A")) + result = test_op(df.groupby("A")) # pass the group in same order as iterating `for ... in df.groupby(...)` # but reorder to match df's index since this is a transform groups = [df[["B"]].iloc[4:6], df[["B"]].iloc[6:], df[["B"]].iloc[:4]] - with tm.assert_produces_warning(warn, match=msg): - expected = concat([mock_op(g) for g in groups]).sort_index() + expected = concat([mock_op(g) for g in groups]).sort_index() # sort_index does not preserve the freq expected = expected.set_axis(df.index) @@ -917,9 +898,7 @@ def test_pad_stable_sorting(fill_method): ], ) @pytest.mark.parametrize("periods", [1, -1]) -@pytest.mark.parametrize("fill_method", ["ffill", "bfill", None]) -@pytest.mark.parametrize("limit", [None, 1]) -def test_pct_change(frame_or_series, freq, periods, fill_method, limit): +def test_pct_change(frame_or_series, freq, periods): # GH 21200, 21621, 30463 vals = [3, np.nan, np.nan, np.nan, 1, 2, 4, 10, np.nan, 4] keys = ["a", "b"] @@ -927,8 +906,6 @@ def test_pct_change(frame_or_series, freq, periods, fill_method, limit): df = DataFrame({"key": key_v, "vals": vals * 2}) df_g = df - if fill_method is not None: - df_g = getattr(df.groupby("key"), fill_method)(limit=limit) grp = df_g.groupby(df.key) expected = grp["vals"].obj / grp["vals"].shift(periods) - 1 @@ -940,14 +917,7 @@ def test_pct_change(frame_or_series, freq, periods, fill_method, limit): else: expected = expected.to_frame("vals") - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - f"{type(gb).__name__}.pct_change are deprecated" - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - result = gb.pct_change( - periods=periods, fill_method=fill_method, limit=limit, freq=freq - ) + result = gb.pct_change(periods=periods, freq=freq) tm.assert_equal(result, expected) @@ -1360,7 +1330,7 @@ def test_null_group_str_reducer(request, dropna, reduction_func): tm.assert_equal(result, expected) -def test_null_group_str_transformer(request, dropna, transformation_func): +def test_null_group_str_transformer(dropna, transformation_func): # GH 17093 df = DataFrame({"A": [1, 1, np.nan], "B": [1, 2, 2]}, index=[1, 2, 3]) args = get_groupby_method_args(transformation_func, df) @@ -1385,21 +1355,7 @@ def test_null_group_str_transformer(request, dropna, transformation_func): # ngroup/cumcount always returns a Series as it counts the groups, not values expected = expected["B"].rename(None) - if transformation_func == "pct_change" and not dropna: - warn = FutureWarning - msg = ( - "The default fill_method='ffill' in DataFrameGroupBy.pct_change " - "is deprecated" - ) - elif transformation_func == "fillna": - warn = FutureWarning - msg = "DataFrameGroupBy.fillna is deprecated" - else: - warn = None - msg = "" - with tm.assert_produces_warning(warn, match=msg): - result = gb.transform(transformation_func, *args) - + result = gb.transform(transformation_func, *args) tm.assert_equal(result, expected) From 9fd23ab507752b298f0f79d937550d2dd1c3c535 Mon Sep 17 00:00:00 2001 From: richard Date: Tue, 5 Mar 2024 22:05:54 -0500 Subject: [PATCH 2/3] Test fixups --- .../tests/series/methods/test_pct_change.py | 74 +++---------------- 1 file changed, 11 insertions(+), 63 deletions(-) diff --git a/pandas/tests/series/methods/test_pct_change.py b/pandas/tests/series/methods/test_pct_change.py index 6c80e711c3684..6279cf64818b8 100644 --- a/pandas/tests/series/methods/test_pct_change.py +++ b/pandas/tests/series/methods/test_pct_change.py @@ -10,23 +10,13 @@ class TestSeriesPctChange: def test_pct_change(self, datetime_series): - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "Series.pct_change are deprecated" - ) - - rs = datetime_series.pct_change(fill_method=None) + rs = datetime_series.pct_change() tm.assert_series_equal(rs, datetime_series / datetime_series.shift(1) - 1) rs = datetime_series.pct_change(2) filled = datetime_series.ffill() tm.assert_series_equal(rs, filled / filled.shift(2) - 1) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs = datetime_series.pct_change(fill_method="bfill", limit=1) - filled = datetime_series.bfill(limit=1) - tm.assert_series_equal(rs, filled / filled.shift(1) - 1) - rs = datetime_series.pct_change(freq="5D") filled = datetime_series.ffill() tm.assert_series_equal( @@ -45,69 +35,27 @@ def test_pct_change_with_duplicate_axis(self): def test_pct_change_shift_over_nas(self): s = Series([1.0, 1.5, np.nan, 2.5, 3.0]) - - msg = "The default fill_method='pad' in Series.pct_change is deprecated" - with tm.assert_produces_warning(FutureWarning, match=msg): - chg = s.pct_change() - - expected = Series([np.nan, 0.5, 0.0, 2.5 / 1.5 - 1, 0.2]) + chg = s.pct_change() + expected = Series([np.nan, 0.5, np.nan, np.nan, 0.2]) tm.assert_series_equal(chg, expected) - @pytest.mark.parametrize( - "freq, periods, fill_method, limit", - [ - ("5B", 5, None, None), - ("3B", 3, None, None), - ("3B", 3, "bfill", None), - ("7B", 7, "pad", 1), - ("7B", 7, "bfill", 3), - ("14B", 14, None, None), - ], - ) - def test_pct_change_periods_freq( - self, freq, periods, fill_method, limit, datetime_series - ): - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "Series.pct_change are deprecated" - ) - + @pytest.mark.parametrize("freq, periods", [("5B", 5), ("3B", 3), ("14B", 14)]) + def test_pct_change_periods_freq(self, freq, periods, datetime_series): # GH#7292 - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_freq = datetime_series.pct_change( - freq=freq, fill_method=fill_method, limit=limit - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_periods = datetime_series.pct_change( - periods, fill_method=fill_method, limit=limit - ) + rs_freq = datetime_series.pct_change(freq=freq) + rs_periods = datetime_series.pct_change(periods) tm.assert_series_equal(rs_freq, rs_periods) empty_ts = Series(index=datetime_series.index, dtype=object) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_freq = empty_ts.pct_change( - freq=freq, fill_method=fill_method, limit=limit - ) - with tm.assert_produces_warning(FutureWarning, match=msg): - rs_periods = empty_ts.pct_change( - periods, fill_method=fill_method, limit=limit - ) + rs_freq = empty_ts.pct_change(freq=freq) + rs_periods = empty_ts.pct_change(periods) tm.assert_series_equal(rs_freq, rs_periods) -@pytest.mark.parametrize("fill_method", ["pad", "ffill", None]) -def test_pct_change_with_duplicated_indices(fill_method): +def test_pct_change_with_duplicated_indices(): # GH30463 s = Series([np.nan, 1, 2, 3, 9, 18], index=["a", "b"] * 3) - - warn = None if fill_method is None else FutureWarning - msg = ( - "The 'fill_method' keyword being not None and the 'limit' keyword in " - "Series.pct_change are deprecated" - ) - with tm.assert_produces_warning(warn, match=msg): - result = s.pct_change(fill_method=fill_method) - + result = s.pct_change() expected = Series([np.nan, np.nan, 1.0, 0.5, 2.0, 1.0], index=["a", "b"] * 3) tm.assert_series_equal(result, expected) From a94ade7e20148fd8038ff5bd90accde662e44259 Mon Sep 17 00:00:00 2001 From: Richard Shadrach Date: Wed, 6 Mar 2024 17:10:22 -0500 Subject: [PATCH 3/3] mypy fixup --- pandas/core/groupby/groupby.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index e77adb5620522..e39523346616c 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -5231,9 +5231,10 @@ def pct_change( return self._python_apply_general(f, self._selected_obj, is_transform=True) if fill_method is None: # GH30463 - fill_method = "ffill" - limit = 0 - filled = getattr(self, fill_method)(limit=limit) + op = "ffill" + else: + op = fill_method + filled = getattr(self, op)(limit=0) fill_grp = filled.groupby(self._grouper.codes, group_keys=self.group_keys) shifted = fill_grp.shift(periods=periods, freq=freq) return (filled / shifted) - 1