Skip to content

Commit dea36ba

Browse files
committed
DEPR fill_method and limit keywords in DataFrame/Series pct_change
1 parent 4d217a4 commit dea36ba

File tree

3 files changed

+111
-28
lines changed

3 files changed

+111
-28
lines changed

pandas/core/generic.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11143,8 +11143,8 @@ def describe(
1114311143
def pct_change(
1114411144
self,
1114511145
periods: int = 1,
11146-
fill_method: Literal["backfill", "bfill", "pad", "ffill"] | None = "pad",
11147-
limit: int | None = None,
11146+
fill_method: FillnaOptions | None | lib.NoDefault = lib.no_default,
11147+
limit: int | None | lib.NoDefault = lib.no_default,
1114811148
freq=None,
1114911149
**kwargs,
1115011150
) -> Self:
@@ -11168,8 +11168,14 @@ def pct_change(
1116811168
Periods to shift for forming percent change.
1116911169
fill_method : {'backfill', 'bfill', 'pad', 'ffill', None}, default 'pad'
1117011170
How to handle NAs **before** computing percent changes.
11171+
11172+
.. deprecated:: 2.1
11173+
1117111174
limit : int, default None
1117211175
The number of consecutive NAs to fill before stopping.
11176+
11177+
.. deprecated:: 2.1
11178+
1117311179
freq : DateOffset, timedelta, or str, optional
1117411180
Increment to use from time series API (e.g. 'M' or BDay()).
1117511181
**kwargs
@@ -11222,7 +11228,7 @@ def pct_change(
1122211228
3 85.0
1122311229
dtype: float64
1122411230
11225-
>>> s.pct_change(fill_method='ffill')
11231+
>>> s.fillna(method='ffill').pct_change()
1122611232
0 NaN
1122711233
1 0.011111
1122811234
2 0.000000
@@ -11269,6 +11275,21 @@ def pct_change(
1126911275
GOOG 0.179241 0.094112 NaN
1127011276
APPL -0.252395 -0.011860 NaN
1127111277
"""
11278+
if fill_method is not lib.no_default or limit is not lib.no_default:
11279+
# GH#53491
11280+
warnings.warn(
11281+
"The 'fill_method' and 'limit' keywords in "
11282+
f"{type(self).__name__}.pct_change are deprecated and will be "
11283+
"removed in a future version. Call fillna directly before "
11284+
"calling pct_change instead.",
11285+
FutureWarning,
11286+
stacklevel=find_stack_level(),
11287+
)
11288+
if fill_method is lib.no_default:
11289+
fill_method = "pad"
11290+
if limit is lib.no_default:
11291+
limit = None
11292+
1127211293
axis = self._get_axis_number(kwargs.pop("axis", "index"))
1127311294
if fill_method is None:
1127411295
data = self

pandas/tests/frame/methods/test_pct_change.py

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class TestDataFramePctChange:
1212
@pytest.mark.parametrize(
13-
"periods,fill_method,limit,exp",
13+
"periods, fill_method, limit, exp",
1414
[
1515
(1, "ffill", None, [np.nan, np.nan, np.nan, 1, 1, 1.5, 0, 0]),
1616
(1, "ffill", 1, [np.nan, np.nan, np.nan, 1, 1, 1.5, 0, np.nan]),
@@ -28,7 +28,12 @@ def test_pct_change_with_nas(
2828
vals = [np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan]
2929
obj = frame_or_series(vals)
3030

31-
res = obj.pct_change(periods=periods, fill_method=fill_method, limit=limit)
31+
msg = (
32+
"The 'fill_method' and 'limit' keywords in "
33+
f"{type(obj).__name__}.pct_change are deprecated"
34+
)
35+
with tm.assert_produces_warning(FutureWarning, match=msg):
36+
res = obj.pct_change(periods=periods, fill_method=fill_method, limit=limit)
3237
tm.assert_equal(res, frame_or_series(exp))
3338

3439
def test_pct_change_numeric(self):
@@ -40,21 +45,34 @@ def test_pct_change_numeric(self):
4045
pnl.iat[1, 1] = np.nan
4146
pnl.iat[2, 3] = 60
4247

48+
msg = (
49+
"The 'fill_method' and 'limit' keywords in "
50+
"DataFrame.pct_change are deprecated"
51+
)
52+
4353
for axis in range(2):
4454
expected = pnl.ffill(axis=axis) / pnl.ffill(axis=axis).shift(axis=axis) - 1
45-
result = pnl.pct_change(axis=axis, fill_method="pad")
4655

56+
with tm.assert_produces_warning(FutureWarning, match=msg):
57+
result = pnl.pct_change(axis=axis, fill_method="pad")
4758
tm.assert_frame_equal(result, expected)
4859

4960
def test_pct_change(self, datetime_frame):
50-
rs = datetime_frame.pct_change(fill_method=None)
61+
msg = (
62+
"The 'fill_method' and 'limit' keywords in "
63+
"DataFrame.pct_change are deprecated"
64+
)
65+
66+
with tm.assert_produces_warning(FutureWarning, match=msg):
67+
rs = datetime_frame.pct_change(fill_method=None)
5168
tm.assert_frame_equal(rs, datetime_frame / datetime_frame.shift(1) - 1)
5269

5370
rs = datetime_frame.pct_change(2)
5471
filled = datetime_frame.fillna(method="pad")
5572
tm.assert_frame_equal(rs, filled / filled.shift(2) - 1)
5673

57-
rs = datetime_frame.pct_change(fill_method="bfill", limit=1)
74+
with tm.assert_produces_warning(FutureWarning, match=msg):
75+
rs = datetime_frame.pct_change(fill_method="bfill", limit=1)
5876
filled = datetime_frame.fillna(method="bfill", limit=1)
5977
tm.assert_frame_equal(rs, filled / filled.shift(1) - 1)
6078

@@ -88,18 +106,31 @@ def test_pct_change_shift_over_nas(self):
88106
def test_pct_change_periods_freq(
89107
self, datetime_frame, freq, periods, fill_method, limit
90108
):
91-
# GH#7292
92-
rs_freq = datetime_frame.pct_change(
93-
freq=freq, fill_method=fill_method, limit=limit
94-
)
95-
rs_periods = datetime_frame.pct_change(
96-
periods, fill_method=fill_method, limit=limit
109+
msg = (
110+
"The 'fill_method' and 'limit' keywords in "
111+
"DataFrame.pct_change are deprecated"
97112
)
113+
114+
# GH#7292
115+
with tm.assert_produces_warning(FutureWarning, match=msg):
116+
rs_freq = datetime_frame.pct_change(
117+
freq=freq, fill_method=fill_method, limit=limit
118+
)
119+
with tm.assert_produces_warning(FutureWarning, match=msg):
120+
rs_periods = datetime_frame.pct_change(
121+
periods, fill_method=fill_method, limit=limit
122+
)
98123
tm.assert_frame_equal(rs_freq, rs_periods)
99124

100125
empty_ts = DataFrame(index=datetime_frame.index, columns=datetime_frame.columns)
101-
rs_freq = empty_ts.pct_change(freq=freq, fill_method=fill_method, limit=limit)
102-
rs_periods = empty_ts.pct_change(periods, fill_method=fill_method, limit=limit)
126+
with tm.assert_produces_warning(FutureWarning, match=msg):
127+
rs_freq = empty_ts.pct_change(
128+
freq=freq, fill_method=fill_method, limit=limit
129+
)
130+
with tm.assert_produces_warning(FutureWarning, match=msg):
131+
rs_periods = empty_ts.pct_change(
132+
periods, fill_method=fill_method, limit=limit
133+
)
103134
tm.assert_frame_equal(rs_freq, rs_periods)
104135

105136

@@ -109,7 +140,14 @@ def test_pct_change_with_duplicated_indices(fill_method):
109140
data = DataFrame(
110141
{0: [np.nan, 1, 2, 3, 9, 18], 1: [0, 1, np.nan, 3, 9, 18]}, index=["a", "b"] * 3
111142
)
112-
result = data.pct_change(fill_method=fill_method)
143+
144+
msg = (
145+
"The 'fill_method' and 'limit' keywords in "
146+
"DataFrame.pct_change are deprecated"
147+
)
148+
with tm.assert_produces_warning(FutureWarning, match=msg):
149+
result = data.pct_change(fill_method=fill_method)
150+
113151
if fill_method is None:
114152
second_column = [np.nan, np.inf, np.nan, np.nan, 2.0, 1.0]
115153
else:

pandas/tests/series/methods/test_pct_change.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,21 @@
1010

1111
class TestSeriesPctChange:
1212
def test_pct_change(self, datetime_series):
13-
rs = datetime_series.pct_change(fill_method=None)
13+
msg = (
14+
"The 'fill_method' and 'limit' keywords in "
15+
"Series.pct_change are deprecated"
16+
)
17+
18+
with tm.assert_produces_warning(FutureWarning, match=msg):
19+
rs = datetime_series.pct_change(fill_method=None)
1420
tm.assert_series_equal(rs, datetime_series / datetime_series.shift(1) - 1)
1521

1622
rs = datetime_series.pct_change(2)
1723
filled = datetime_series.fillna(method="pad")
1824
tm.assert_series_equal(rs, filled / filled.shift(2) - 1)
1925

20-
rs = datetime_series.pct_change(fill_method="bfill", limit=1)
26+
with tm.assert_produces_warning(FutureWarning, match=msg):
27+
rs = datetime_series.pct_change(fill_method="bfill", limit=1)
2128
filled = datetime_series.fillna(method="bfill", limit=1)
2229
tm.assert_series_equal(rs, filled / filled.shift(1) - 1)
2330

@@ -58,25 +65,42 @@ def test_pct_change_shift_over_nas(self):
5865
def test_pct_change_periods_freq(
5966
self, freq, periods, fill_method, limit, datetime_series
6067
):
61-
# GH#7292
62-
rs_freq = datetime_series.pct_change(
63-
freq=freq, fill_method=fill_method, limit=limit
64-
)
65-
rs_periods = datetime_series.pct_change(
66-
periods, fill_method=fill_method, limit=limit
68+
msg = (
69+
"The 'fill_method' and 'limit' keywords in "
70+
"Series.pct_change are deprecated"
6771
)
72+
73+
# GH#7292
74+
with tm.assert_produces_warning(FutureWarning, match=msg):
75+
rs_freq = datetime_series.pct_change(
76+
freq=freq, fill_method=fill_method, limit=limit
77+
)
78+
with tm.assert_produces_warning(FutureWarning, match=msg):
79+
rs_periods = datetime_series.pct_change(
80+
periods, fill_method=fill_method, limit=limit
81+
)
6882
tm.assert_series_equal(rs_freq, rs_periods)
6983

7084
empty_ts = Series(index=datetime_series.index, dtype=object)
71-
rs_freq = empty_ts.pct_change(freq=freq, fill_method=fill_method, limit=limit)
72-
rs_periods = empty_ts.pct_change(periods, fill_method=fill_method, limit=limit)
85+
with tm.assert_produces_warning(FutureWarning, match=msg):
86+
rs_freq = empty_ts.pct_change(
87+
freq=freq, fill_method=fill_method, limit=limit
88+
)
89+
with tm.assert_produces_warning(FutureWarning, match=msg):
90+
rs_periods = empty_ts.pct_change(
91+
periods, fill_method=fill_method, limit=limit
92+
)
7393
tm.assert_series_equal(rs_freq, rs_periods)
7494

7595

7696
@pytest.mark.parametrize("fill_method", ["pad", "ffill", None])
7797
def test_pct_change_with_duplicated_indices(fill_method):
7898
# GH30463
7999
s = Series([np.nan, 1, 2, 3, 9, 18], index=["a", "b"] * 3)
80-
result = s.pct_change(fill_method=fill_method)
100+
101+
msg = "The 'fill_method' and 'limit' keywords in Series.pct_change are deprecated"
102+
with tm.assert_produces_warning(FutureWarning, match=msg):
103+
result = s.pct_change(fill_method=fill_method)
104+
81105
expected = Series([np.nan, np.nan, 1.0, 0.5, 2.0, 1.0], index=["a", "b"] * 3)
82106
tm.assert_series_equal(result, expected)

0 commit comments

Comments
 (0)