Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added negative value support in pct_changes of generic.py #56627

Closed
6 changes: 5 additions & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -11975,6 +11975,7 @@ def pct_change(
fill_method: FillnaOptions | None | lib.NoDefault = lib.no_default,
limit: int | None | lib.NoDefault = lib.no_default,
freq=None,
use_absolute_value=False,
**kwargs,
) -> Self:
"""
Expand Down Expand Up @@ -12145,7 +12146,10 @@ def pct_change(

shifted = data.shift(periods=periods, freq=freq, axis=axis, **kwargs)
# Unsupported left operand type for / ("Self")
rs = data / shifted - 1 # type: ignore[operator]
if use_absolute_value:
rs = (data - shifted) / abs(shifted) # type: ignore[operator]
else:
rs = data / 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
Expand Down
4 changes: 4 additions & 0 deletions pandas/core/groupby/groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -5331,6 +5331,7 @@ def pct_change(
fill_method: FillnaOptions | None | lib.NoDefault = lib.no_default,
limit: int | None | lib.NoDefault = lib.no_default,
freq=None,
use_absolute_value=False,
axis: Axis | lib.NoDefault = lib.no_default,
):
"""
Expand Down Expand Up @@ -5422,6 +5423,7 @@ def pct_change(
limit=limit,
freq=freq,
axis=axis,
use_absolute_value=use_absolute_value,
)
return self._python_apply_general(f, self._selected_obj, is_transform=True)

Expand All @@ -5436,6 +5438,8 @@ def pct_change(
shifted = fill_grp.shift(periods=periods, freq=freq)
if self.axis == 1:
shifted = shifted.T
if use_absolute_value:
return (filled - shifted) / abs(shifted)
return (filled / shifted) - 1

@final
Expand Down
33 changes: 29 additions & 4 deletions pandas/tests/series/methods/test_pct_change.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import numpy as np
import pytest

import pandas as pd
from pandas import (
Series,
date_range,
Expand Down Expand Up @@ -75,22 +76,30 @@ def test_pct_change_periods_freq(
# GH#7292
with tm.assert_produces_warning(FutureWarning, match=msg):
rs_freq = datetime_series.pct_change(
freq=freq, fill_method=fill_method, limit=limit
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
periods,
fill_method=fill_method,
limit=limit,
)
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
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
periods,
fill_method=fill_method,
limit=limit,
)
tm.assert_series_equal(rs_freq, rs_periods)

Expand Down Expand Up @@ -118,3 +127,19 @@ def test_pct_change_no_warning_na_beginning():
result = ser.pct_change()
expected = Series([np.nan, np.nan, np.nan, 1, 0.5])
tm.assert_series_equal(result, expected)


def test_pct_changes_with_negative_values():
test = pd.DataFrame()
test_list = [1, -2, 3, 4, -5, 6, 7, -8, 9, 10]
test["data"] = test_list
test["pct_changes"] = test["data"].pct_change(use_absolute_value=True)

expected_result = [
None if i == 0 else (test_list[i] - test_list[i - 1]) / abs(test_list[i - 1])
for i in range(len(test_list))
]

expected_result = Series(expected_result, dtype=float)
# assertion to check if the result matches the expected result
assert test["pct_changes"].equals(expected_result)
Loading