Skip to content

Commit 47a7cbf

Browse files
Backport PR #55527: BUG fix deprecation of limit and fill_method … (#55701)
Backport PR #55527: BUG fix deprecation of `limit` and `fill_method` in `pct_change` Co-authored-by: Yao Xiao <[email protected]>
1 parent bceb84b commit 47a7cbf

File tree

6 files changed

+63
-47
lines changed

6 files changed

+63
-47
lines changed

doc/source/whatsnew/v2.1.2.rst

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ including other versions of pandas.
88

99
{{ header }}
1010

11+
.. ---------------------------------------------------------------------------
12+
.. _whatsnew_212.deprecations:
13+
14+
Deprecations
15+
~~~~~~~~~~~~
16+
17+
- Reverted deprecation of ``fill_method=None`` in :meth:`DataFrame.pct_change`, :meth:`Series.pct_change`, :meth:`DataFrameGroupBy.pct_change`, and :meth:`SeriesGroupBy.pct_change`; the values ``'backfill'``, ``'bfill'``, ``'pad'``, and ``'ffill'`` are still deprecated (:issue:`53491`)
18+
1119
.. ---------------------------------------------------------------------------
1220
.. _whatsnew_212.regressions:
1321

pandas/core/generic.py

+23-21
Original file line numberDiff line numberDiff line change
@@ -11579,6 +11579,7 @@ def pct_change(
1157911579
How to handle NAs **before** computing percent changes.
1158011580
1158111581
.. deprecated:: 2.1
11582+
All options of `fill_method` are deprecated except `fill_method=None`.
1158211583
1158311584
limit : int, default None
1158411585
The number of consecutive NAs to fill before stopping.
@@ -11685,32 +11686,33 @@ def pct_change(
1168511686
APPL -0.252395 -0.011860 NaN
1168611687
"""
1168711688
# GH#53491
11688-
if fill_method is not lib.no_default or limit is not lib.no_default:
11689+
if fill_method not in (lib.no_default, None) or limit is not lib.no_default:
1168911690
warnings.warn(
11690-
"The 'fill_method' and 'limit' keywords in "
11691-
f"{type(self).__name__}.pct_change are deprecated and will be "
11692-
"removed in a future version. Call "
11693-
f"{'bfill' if fill_method in ('backfill', 'bfill') else 'ffill'} "
11694-
"before calling pct_change instead.",
11691+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
11692+
f"{type(self).__name__}.pct_change are deprecated and will be removed "
11693+
"in a future version. Either fill in any non-leading NA values prior "
11694+
"to calling pct_change or specify 'fill_method=None' to not fill NA "
11695+
"values.",
1169511696
FutureWarning,
1169611697
stacklevel=find_stack_level(),
1169711698
)
1169811699
if fill_method is lib.no_default:
11699-
cols = self.items() if self.ndim == 2 else [(None, self)]
11700-
for _, col in cols:
11701-
mask = col.isna().values
11702-
mask = mask[np.argmax(~mask) :]
11703-
if mask.any():
11704-
warnings.warn(
11705-
"The default fill_method='pad' in "
11706-
f"{type(self).__name__}.pct_change is deprecated and will be "
11707-
"removed in a future version. Call ffill before calling "
11708-
"pct_change to retain current behavior and silence this "
11709-
"warning.",
11710-
FutureWarning,
11711-
stacklevel=find_stack_level(),
11712-
)
11713-
break
11700+
if limit is lib.no_default:
11701+
cols = self.items() if self.ndim == 2 else [(None, self)]
11702+
for _, col in cols:
11703+
mask = col.isna().values
11704+
mask = mask[np.argmax(~mask) :]
11705+
if mask.any():
11706+
warnings.warn(
11707+
"The default fill_method='pad' in "
11708+
f"{type(self).__name__}.pct_change is deprecated and will "
11709+
"be removed in a future version. Either fill in any "
11710+
"non-leading NA values prior to calling pct_change or "
11711+
"specify 'fill_method=None' to not fill NA values.",
11712+
FutureWarning,
11713+
stacklevel=find_stack_level(),
11714+
)
11715+
break
1171411716
fill_method = "pad"
1171511717
if limit is lib.no_default:
1171611718
limit = None

pandas/core/groupby/groupby.py

+14-11
Original file line numberDiff line numberDiff line change
@@ -5217,7 +5217,7 @@ def diff(
52175217
def pct_change(
52185218
self,
52195219
periods: int = 1,
5220-
fill_method: FillnaOptions | lib.NoDefault = lib.no_default,
5220+
fill_method: FillnaOptions | None | lib.NoDefault = lib.no_default,
52215221
limit: int | None | lib.NoDefault = lib.no_default,
52225222
freq=None,
52235223
axis: Axis | lib.NoDefault = lib.no_default,
@@ -5269,23 +5269,26 @@ def pct_change(
52695269
goldfish 0.2 0.125
52705270
"""
52715271
# GH#53491
5272-
if fill_method is not lib.no_default or limit is not lib.no_default:
5272+
if fill_method not in (lib.no_default, None) or limit is not lib.no_default:
52735273
warnings.warn(
5274-
"The 'fill_method' and 'limit' keywords in "
5275-
f"{type(self).__name__}.pct_change are deprecated and will be "
5276-
"removed in a future version. Call "
5277-
f"{'bfill' if fill_method in ('backfill', 'bfill') else 'ffill'} "
5278-
"before calling pct_change instead.",
5274+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
5275+
f"{type(self).__name__}.pct_change are deprecated and will be removed "
5276+
"in a future version. Either fill in any non-leading NA values prior "
5277+
"to calling pct_change or specify 'fill_method=None' to not fill NA "
5278+
"values.",
52795279
FutureWarning,
52805280
stacklevel=find_stack_level(),
52815281
)
52825282
if fill_method is lib.no_default:
5283-
if any(grp.isna().values.any() for _, grp in self):
5283+
if limit is lib.no_default and any(
5284+
grp.isna().values.any() for _, grp in self
5285+
):
52845286
warnings.warn(
52855287
"The default fill_method='ffill' in "
5286-
f"{type(self).__name__}.pct_change is deprecated and will be "
5287-
"removed in a future version. Call ffill before calling "
5288-
"pct_change to retain current behavior and silence this warning.",
5288+
f"{type(self).__name__}.pct_change is deprecated and will "
5289+
"be removed in a future version. Either fill in any "
5290+
"non-leading NA values prior to calling pct_change or "
5291+
"specify 'fill_method=None' to not fill NA values.",
52895292
FutureWarning,
52905293
stacklevel=find_stack_level(),
52915294
)

pandas/tests/frame/methods/test_pct_change.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_pct_change_with_nas(
2929
obj = frame_or_series(vals)
3030

3131
msg = (
32-
"The 'fill_method' and 'limit' keywords in "
32+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
3333
f"{type(obj).__name__}.pct_change are deprecated"
3434
)
3535
with tm.assert_produces_warning(FutureWarning, match=msg):
@@ -46,7 +46,7 @@ def test_pct_change_numeric(self):
4646
pnl.iat[2, 3] = 60
4747

4848
msg = (
49-
"The 'fill_method' and 'limit' keywords in "
49+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
5050
"DataFrame.pct_change are deprecated"
5151
)
5252

@@ -59,12 +59,11 @@ def test_pct_change_numeric(self):
5959

6060
def test_pct_change(self, datetime_frame):
6161
msg = (
62-
"The 'fill_method' and 'limit' keywords in "
62+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
6363
"DataFrame.pct_change are deprecated"
6464
)
6565

66-
with tm.assert_produces_warning(FutureWarning, match=msg):
67-
rs = datetime_frame.pct_change(fill_method=None)
66+
rs = datetime_frame.pct_change(fill_method=None)
6867
tm.assert_frame_equal(rs, datetime_frame / datetime_frame.shift(1) - 1)
6968

7069
rs = datetime_frame.pct_change(2)
@@ -110,7 +109,7 @@ def test_pct_change_periods_freq(
110109
self, datetime_frame, freq, periods, fill_method, limit
111110
):
112111
msg = (
113-
"The 'fill_method' and 'limit' keywords in "
112+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
114113
"DataFrame.pct_change are deprecated"
115114
)
116115

@@ -144,11 +143,12 @@ def test_pct_change_with_duplicated_indices(fill_method):
144143
{0: [np.nan, 1, 2, 3, 9, 18], 1: [0, 1, np.nan, 3, 9, 18]}, index=["a", "b"] * 3
145144
)
146145

146+
warn = None if fill_method is None else FutureWarning
147147
msg = (
148-
"The 'fill_method' and 'limit' keywords in "
148+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
149149
"DataFrame.pct_change are deprecated"
150150
)
151-
with tm.assert_produces_warning(FutureWarning, match=msg):
151+
with tm.assert_produces_warning(warn, match=msg):
152152
result = data.pct_change(fill_method=fill_method)
153153

154154
if fill_method is None:

pandas/tests/groupby/transform/test_transform.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ def test_pct_change(frame_or_series, freq, periods, fill_method, limit):
10631063
expected = expected.to_frame("vals")
10641064

10651065
msg = (
1066-
"The 'fill_method' and 'limit' keywords in "
1066+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
10671067
f"{type(gb).__name__}.pct_change are deprecated"
10681068
)
10691069
with tm.assert_produces_warning(FutureWarning, match=msg):

pandas/tests/series/methods/test_pct_change.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
class TestSeriesPctChange:
1212
def test_pct_change(self, datetime_series):
1313
msg = (
14-
"The 'fill_method' and 'limit' keywords in "
14+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
1515
"Series.pct_change are deprecated"
1616
)
1717

18-
with tm.assert_produces_warning(FutureWarning, match=msg):
19-
rs = datetime_series.pct_change(fill_method=None)
18+
rs = datetime_series.pct_change(fill_method=None)
2019
tm.assert_series_equal(rs, datetime_series / datetime_series.shift(1) - 1)
2120

2221
rs = datetime_series.pct_change(2)
@@ -69,7 +68,7 @@ def test_pct_change_periods_freq(
6968
self, freq, periods, fill_method, limit, datetime_series
7069
):
7170
msg = (
72-
"The 'fill_method' and 'limit' keywords in "
71+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
7372
"Series.pct_change are deprecated"
7473
)
7574

@@ -101,8 +100,12 @@ def test_pct_change_with_duplicated_indices(fill_method):
101100
# GH30463
102101
s = Series([np.nan, 1, 2, 3, 9, 18], index=["a", "b"] * 3)
103102

104-
msg = "The 'fill_method' and 'limit' keywords in Series.pct_change are deprecated"
105-
with tm.assert_produces_warning(FutureWarning, match=msg):
103+
warn = None if fill_method is None else FutureWarning
104+
msg = (
105+
"The 'fill_method' keyword being not None and the 'limit' keyword in "
106+
"Series.pct_change are deprecated"
107+
)
108+
with tm.assert_produces_warning(warn, match=msg):
106109
result = s.pct_change(fill_method=fill_method)
107110

108111
expected = Series([np.nan, np.nan, 1.0, 0.5, 2.0, 1.0], index=["a", "b"] * 3)

0 commit comments

Comments
 (0)