From 3e90a888f7e3fee96a2ae4d9ad68bb2303cd05a3 Mon Sep 17 00:00:00 2001 From: Bert Palm Date: Fri, 8 Oct 2021 15:40:28 +0200 Subject: [PATCH 1/3] fixed rolling for a decreasing index, added a test for that --- pandas/_libs/window/indexers.pyx | 6 ++++-- pandas/tests/window/test_rolling.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/window/indexers.pyx b/pandas/_libs/window/indexers.pyx index 197345b3ce6ac..3782b55bd19b3 100644 --- a/pandas/_libs/window/indexers.pyx +++ b/pandas/_libs/window/indexers.pyx @@ -81,9 +81,11 @@ def calculate_variable_window_bounds( if center: end_bound = index[0] + index_growth_sign * window_size / 2 for j in range(0, num_values): - if (index[j] < end_bound) or (index[j] == end_bound and right_closed): + if (index[j] - end_bound) * index_growth_sign < 0: end[0] = j + 1 - elif index[j] >= end_bound: + elif (index[j] - end_bound) * index_growth_sign == 0 and right_closed: + end[0] = j + 1 + elif (index[j] - end_bound) * index_growth_sign >= 0: end[0] = j break diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index 1631c9f0e2ffd..1c1ed15f6d04d 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -1210,6 +1210,22 @@ def test_rolling_decreasing_indices(method): assert np.abs(decreasing.values[::-1][:-4] - increasing.values[4:]).max() < 1e-12 +@pytest.mark.parametrize("window", ["0s", "2s", "3s"]) +def test_rolling_decreasing_indices_invariant(window, center, closed): + """ + Ensure that a symmetrical inverted index return same result as non-inverted. + """ + + index = date_range("2020", periods=4, freq="1s") + df_inc = Series(range(4), index=index) + df_dec = Series(range(4), index=index[::-1]) + + result = df_dec.rolling(window, closed=closed, center=center).sum() + expected = df_inc.rolling(window, closed=closed, center=center).sum() + + tm.assert_equal(result.values, expected.values) + + @pytest.mark.parametrize( "method,expected", [ From 453d1d3dc58c7971433eca334dcd619989bc1833 Mon Sep 17 00:00:00 2001 From: Bert Palm Date: Sat, 9 Oct 2021 00:26:01 +0200 Subject: [PATCH 2/3] fixed test according to suggestions in MR --- pandas/tests/window/test_rolling.py | 31 ++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index 1c1ed15f6d04d..d88ce2ccb54cc 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -1210,20 +1210,37 @@ def test_rolling_decreasing_indices(method): assert np.abs(decreasing.values[::-1][:-4] - increasing.values[4:]).max() < 1e-12 -@pytest.mark.parametrize("window", ["0s", "2s", "3s"]) -def test_rolling_decreasing_indices_invariant(window, center, closed): +@pytest.mark.parametrize( + "window,closed,expected", + [ + ("2s", "right", [1.0, 3.0, 5.0, 3.0]), + ("2s", "left", [0.0, 1.0, 3.0, 5.0]), + ("2s", "both", [1.0, 3.0, 6.0, 5.0]), + ("2s", "neither", [0.0, 1.0, 2.0, 3.0]), + ("3s", "right", [1.0, 3.0, 6.0, 5.0]), + ("3s", "left", [1.0, 3.0, 6.0, 5.0]), + ("3s", "both", [1.0, 3.0, 6.0, 5.0]), + ("3s", "neither", [1.0, 3.0, 6.0, 5.0]), + ], +) +def test_rolling_decreasing_indices_centered(window, closed, expected, frame_or_series): """ Ensure that a symmetrical inverted index return same result as non-inverted. """ + # GH 43927 index = date_range("2020", periods=4, freq="1s") - df_inc = Series(range(4), index=index) - df_dec = Series(range(4), index=index[::-1]) + df_inc = frame_or_series(range(4), index=index) + df_dec = frame_or_series(range(4), index=index[::-1]) + + expected_inc = frame_or_series(expected, index=index) + expected_dec = frame_or_series(expected, index=index[::-1]) - result = df_dec.rolling(window, closed=closed, center=center).sum() - expected = df_inc.rolling(window, closed=closed, center=center).sum() + result_inc = df_inc.rolling(window, closed=closed, center=True).sum() + result_dec = df_dec.rolling(window, closed=closed, center=True).sum() - tm.assert_equal(result.values, expected.values) + tm.assert_equal(result_inc, expected_inc) + tm.assert_equal(result_dec, expected_dec) @pytest.mark.parametrize( From 2d6c77b719b2bf06a48bec6a537566fb541b923a Mon Sep 17 00:00:00 2001 From: Bert Palm Date: Sat, 9 Oct 2021 01:13:31 +0200 Subject: [PATCH 3/3] added entry to whats new --- doc/source/whatsnew/v1.4.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 722d0dcc10041..e638a24f830ef 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -502,6 +502,7 @@ Groupby/resample/rolling - Bug in :meth:`DataFrame.groupby.rolling` when specifying ``on`` and calling ``__getitem__`` would subsequently return incorrect results (:issue:`43355`) - Bug in :meth:`GroupBy.apply` with time-based :class:`Grouper` objects incorrectly raising ``ValueError`` in corner cases where the grouping vector contains a ``NaT`` (:issue:`43500`, :issue:`43515`) - Bug in :meth:`GroupBy.mean` failing with ``complex`` dtype (:issue:`43701`) +- Fixed bug in :meth:`Series.rolling` and :meth:`DataFrame.rolling` not calculating window bounds correctly for the first row when ``center=True`` and index is decreasing (:issue:`43927`) Reshaping ^^^^^^^^^