import numpy as np
import pytest
from pandas import (
DataFrame,
Series,
)
import pandas._testing as tm
class TestDataFramePctChange:
@pytest.mark.parametrize(
"periods, fill_method, limit, 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]),
],
)
def test_pct_change_with_nas(
self, periods, fill_method, limit, 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)
tm.assert_equal(res, frame_or_series(exp))
def test_pct_change_numeric(self):
# GH#11150
pnl = DataFrame(
[np.arange(0, 40, 10), np.arange(0, 40, 10), np.arange(0, 40, 10)]
).astype(np.float64)
pnl.iat[1, 0] = np.nan
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")
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)
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(freq="5D")
filled = datetime_frame.ffill()
tm.assert_frame_equal(
rs, (filled / filled.shift(freq="5D") - 1).reindex_like(filled)
)
def test_pct_change_shift_over_nas(self):
s = Series([1.0, 1.5, np.nan, 2.5, 3.0])
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])
edf = DataFrame({"a": expected, "b": expected})
tm.assert_frame_equal(chg, edf)
@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, datetime_frame, freq, periods, fill_method, limit
):
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
)
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
)
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):
# 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)
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]
expected = DataFrame(
{0: [np.nan, np.nan, 1.0, 0.5, 2.0, 1.0], 1: second_column},
index=["a", "b"] * 3,
)
tm.assert_frame_equal(result, expected)
def test_pct_change_none_beginning_no_warning():
# GH#54481
df = DataFrame(
[
[1, None],
[2, 1],
[3, 2],
[4, 3],
[5, 4],
]
)
result = df.pct_change()
expected = DataFrame(
{0: [np.nan, 1, 0.5, 1 / 3, 0.25], 1: [np.nan, np.nan, 1, 0.5, 1 / 3]}
)
tm.assert_frame_equal(result, expected)
|