From e6237e59221c6a8b547146df32893b27e36e83dd Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 23 Feb 2018 16:07:42 -0800 Subject: [PATCH 1/7] Added test cases for pct_change op --- pandas/tests/generic/test_generic.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index 3868bdf7d4620..015c3788a19b5 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -592,6 +592,32 @@ def test_copy_and_deepcopy(self): assert obj_copy is not obj self._compare(obj_copy, obj) + @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, -.5, -.5, -.6, 0, 0, np.nan]), + (-1, "ffill", 1, [np.nan, np.nan, -.5, -.5, -.6, 0, np.nan, np.nan]), + (-1, "bfill", None, [0, 0, -.5, -.5, -.6, np.nan, np.nan, np.nan]), + (-1, "bfill", 1, [np.nan, 0, -.5, -.5, -.6, np.nan, np.nan, np.nan]) + ]) + def test_pct_change(self, periods, fill_method, limit, exp): + obj = self._construct(0) + if type(obj) is Panel: + pytest.skip("Not testing deprecated Panel") + is_frame = type(obj) is DataFrame + ser = pd.Series([np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan]) + obj = pd.concat((obj, ser)) + + func = getattr(obj, 'pct_change') + res = func(periods=periods, fill_method=fill_method, limit=limit) + + # Convert output into Series, regardless of input type + if is_frame: + res = res[0] + res.name = None + tm.assert_series_equal(res, pd.Series(exp)) class TestNDFrame(object): # tests that don't fit elsewhere From 84ffd53eddee9689eca539b12eb839356dcd5114 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 23 Feb 2018 16:08:31 -0800 Subject: [PATCH 2/7] Fixed fill_method arg in pct_change --- pandas/core/generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 85e2ce475ffa2..e1ed6ae9c8a6c 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -7488,7 +7488,7 @@ def pct_change(self, periods=1, fill_method='pad', limit=None, freq=None, **kwargs)) - 1) rs = rs.reindex_like(data) if freq is None: - mask = isna(com._values_from_object(self)) + mask = isna(com._values_from_object(data)) np.putmask(rs.values, mask, np.nan) return rs From f6a35a6c3aa8d6dcd579475e1a55059f875c3c75 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 23 Feb 2018 16:09:10 -0800 Subject: [PATCH 3/7] LINT fix --- pandas/tests/generic/test_generic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index 015c3788a19b5..b7b44fc4fc0a3 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -619,6 +619,7 @@ def test_pct_change(self, periods, fill_method, limit, exp): res.name = None tm.assert_series_equal(res, pd.Series(exp)) + class TestNDFrame(object): # tests that don't fit elsewhere From ca56ca4b8e09cb0d5878286946f548496db6a3ac Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 23 Feb 2018 16:19:18 -0800 Subject: [PATCH 4/7] Updated whatsnew --- doc/source/whatsnew/v0.23.0.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index fd3c3a5a7a301..ed37892aeff9e 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -807,6 +807,7 @@ Numeric - Bug in :class:`Index` constructor with ``dtype='uint64'`` where int-like floats were not coerced to :class:`UInt64Index` (:issue:`18400`) - Bug in :class:`DataFrame` flex arithmetic (e.g. ``df.add(other, fill_value=foo)``) with a ``fill_value`` other than ``None`` failed to raise ``NotImplementedError`` in corner cases where either the frame or ``other`` has length zero (:issue:`19522`) - Multiplication and division of numeric-dtyped :class:`Index` objects with timedelta-like scalars returns ``TimedeltaIndex`` instead of raising ``TypeError`` (:issue:`19333`) +- Bug where ``NaN`` was returned instead of 0 by :func:`Series.pct_change` and :func:`DataFrame.pct_change` when ``fill_method`` is not ``None`` (provided) (:issue:`19873`) Indexing From 48bb137139a2279591b8319151f328332b07b710 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 23 Feb 2018 16:43:18 -0800 Subject: [PATCH 5/7] Added new test to Panel section --- pandas/tests/generic/test_generic.py | 2 -- pandas/tests/generic/test_panel.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index b7b44fc4fc0a3..d838918384945 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -604,8 +604,6 @@ def test_copy_and_deepcopy(self): ]) def test_pct_change(self, periods, fill_method, limit, exp): obj = self._construct(0) - if type(obj) is Panel: - pytest.skip("Not testing deprecated Panel") is_frame = type(obj) is DataFrame ser = pd.Series([np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan]) obj = pd.concat((obj, ser)) diff --git a/pandas/tests/generic/test_panel.py b/pandas/tests/generic/test_panel.py index 4cbd5cb2aa69f..49cb773a1bd10 100644 --- a/pandas/tests/generic/test_panel.py +++ b/pandas/tests/generic/test_panel.py @@ -45,7 +45,7 @@ def test_to_xarray(self): 'test_stat_non_defaults_args', 'test_truncate_out_of_bounds', 'test_metadata_propagation', 'test_copy_and_deepcopy', - 'test_sample']: + 'test_pct_change', 'test_sample']: def f(): def tester(self): From 9e9c2958b4c8a012cf4a587241be47efd29783a7 Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Fri, 23 Feb 2018 20:30:48 -0800 Subject: [PATCH 6/7] Updated existing test failures --- pandas/tests/frame/test_analytics.py | 3 --- pandas/tests/frame/test_timeseries.py | 2 +- pandas/tests/series/test_timeseries.py | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pandas/tests/frame/test_analytics.py b/pandas/tests/frame/test_analytics.py index f2b8387072c8d..de4a132e0d613 100644 --- a/pandas/tests/frame/test_analytics.py +++ b/pandas/tests/frame/test_analytics.py @@ -1941,12 +1941,9 @@ def test_pct_change(self): pnl.iat[1, 1] = np.nan pnl.iat[2, 3] = 60 - mask = pnl.isnull() - for axis in range(2): expected = pnl.ffill(axis=axis) / pnl.ffill(axis=axis).shift( axis=axis) - 1 - expected[mask] = np.nan result = pnl.pct_change(axis=axis, fill_method='pad') tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/frame/test_timeseries.py b/pandas/tests/frame/test_timeseries.py index 25dd285e883a0..9f94439a71a57 100644 --- a/pandas/tests/frame/test_timeseries.py +++ b/pandas/tests/frame/test_timeseries.py @@ -118,7 +118,7 @@ def test_pct_change_shift_over_nas(self): df = DataFrame({'a': s, 'b': s}) chg = df.pct_change() - expected = Series([np.nan, 0.5, np.nan, 2.5 / 1.5 - 1, .2]) + expected = Series([np.nan, 0.5, 0., 2.5 / 1.5 - 1, .2]) edf = DataFrame({'a': expected, 'b': expected}) assert_frame_equal(chg, edf) diff --git a/pandas/tests/series/test_timeseries.py b/pandas/tests/series/test_timeseries.py index 7a1aff1cc223c..63a05ef7de565 100644 --- a/pandas/tests/series/test_timeseries.py +++ b/pandas/tests/series/test_timeseries.py @@ -352,7 +352,7 @@ def test_pct_change_shift_over_nas(self): s = Series([1., 1.5, np.nan, 2.5, 3.]) chg = s.pct_change() - expected = Series([np.nan, 0.5, np.nan, 2.5 / 1.5 - 1, .2]) + expected = Series([np.nan, 0.5, 0., 2.5 / 1.5 - 1, .2]) assert_series_equal(chg, expected) def test_pct_change_periods_freq(self): From d68738356f444ff564e9c36fef54c555bd96528f Mon Sep 17 00:00:00 2001 From: Will Ayd Date: Sat, 24 Feb 2018 15:51:39 -0800 Subject: [PATCH 7/7] Refactored test_pct_change --- pandas/tests/generic/test_generic.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index d838918384945..311c71f734945 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -603,19 +603,14 @@ def test_copy_and_deepcopy(self): (-1, "bfill", 1, [np.nan, 0, -.5, -.5, -.6, np.nan, np.nan, np.nan]) ]) def test_pct_change(self, periods, fill_method, limit, exp): - obj = self._construct(0) - is_frame = type(obj) is DataFrame - ser = pd.Series([np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan]) - obj = pd.concat((obj, ser)) - + vals = [np.nan, np.nan, 1, 2, 4, 10, np.nan, np.nan] + obj = self._typ(vals) func = getattr(obj, 'pct_change') res = func(periods=periods, fill_method=fill_method, limit=limit) - - # Convert output into Series, regardless of input type - if is_frame: - res = res[0] - res.name = None - tm.assert_series_equal(res, pd.Series(exp)) + if type(obj) is DataFrame: + tm.assert_frame_equal(res, DataFrame(exp)) + else: + tm.assert_series_equal(res, Series(exp)) class TestNDFrame(object):