From b487d128900a035ca55f5ff685a7c7fce963fed9 Mon Sep 17 00:00:00 2001 From: Bert Palm Date: Sat, 9 Oct 2021 23:54:22 +0200 Subject: [PATCH 1/3] [FIX] rolling now respect duplicate datetime indices on the right bound of centered windows. --- pandas/_libs/window/indexers.pyx | 1 - pandas/tests/window/test_rolling.py | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/window/indexers.pyx b/pandas/_libs/window/indexers.pyx index 3782b55bd19b3..59889cb58c3d5 100644 --- a/pandas/_libs/window/indexers.pyx +++ b/pandas/_libs/window/indexers.pyx @@ -122,7 +122,6 @@ def calculate_variable_window_bounds( elif ((index[j] - end_bound) * index_growth_sign == 0 and right_closed): end[i] = j + 1 - break elif (index[j] - end_bound) * index_growth_sign >= 0: end[i] = j break diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index d88ce2ccb54cc..654518594be3e 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -250,6 +250,33 @@ def test_datetimelike_centered_offset_covers_all( tm.assert_equal(result, expected) +@pytest.mark.parametrize( + "window,closed,expected", + [ + ("2D", "right", [4, 4, 4, 4, 4, 4, 2, 2]), + ("2D", "left", [2, 2, 4, 4, 4, 4, 4, 4]), + ("2D", "both", [4, 4, 6, 6, 6, 6, 4, 4]), + ("2D", "neither", [2, 2, 2, 2, 2, 2, 2, 2]), + ], +) +def test_datetimelike_nonunique_index_centering( + window, closed, expected, frame_or_series +): + index = DatetimeIndex([ + '2020-01-01', '2020-01-01', + '2020-01-02', '2020-01-02', + '2020-01-03', '2020-01-03', + '2020-01-04', '2020-01-04', + ]) + + df = frame_or_series([1]*8, index=index, dtype=float) + expected = frame_or_series(expected, index=index, dtype=float) + + result = df.rolling(window, center=True, closed=closed).sum() + + tm.assert_equal(result, expected) + + def test_even_number_window_alignment(): # see discussion in GH 38780 s = Series(range(3), index=date_range(start="2020-01-01", freq="D", periods=3)) From 927a68c14ced8a4457b044e697b683c550020245 Mon Sep 17 00:00:00 2001 From: Bert Palm Date: Sun, 10 Oct 2021 00:45:25 +0200 Subject: [PATCH 2/3] blackified --- pandas/tests/window/test_rolling.py | 30 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index 654518594be3e..6028e89bea374 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -253,23 +253,29 @@ def test_datetimelike_centered_offset_covers_all( @pytest.mark.parametrize( "window,closed,expected", [ - ("2D", "right", [4, 4, 4, 4, 4, 4, 2, 2]), - ("2D", "left", [2, 2, 4, 4, 4, 4, 4, 4]), - ("2D", "both", [4, 4, 6, 6, 6, 6, 4, 4]), + ("2D", "right", [4, 4, 4, 4, 4, 4, 2, 2]), + ("2D", "left", [2, 2, 4, 4, 4, 4, 4, 4]), + ("2D", "both", [4, 4, 6, 6, 6, 6, 4, 4]), ("2D", "neither", [2, 2, 2, 2, 2, 2, 2, 2]), ], ) def test_datetimelike_nonunique_index_centering( - window, closed, expected, frame_or_series + window, closed, expected, frame_or_series ): - index = DatetimeIndex([ - '2020-01-01', '2020-01-01', - '2020-01-02', '2020-01-02', - '2020-01-03', '2020-01-03', - '2020-01-04', '2020-01-04', - ]) - - df = frame_or_series([1]*8, index=index, dtype=float) + index = DatetimeIndex( + [ + "2020-01-01", + "2020-01-01", + "2020-01-02", + "2020-01-02", + "2020-01-03", + "2020-01-03", + "2020-01-04", + "2020-01-04", + ] + ) + + df = frame_or_series([1] * 8, index=index, dtype=float) expected = frame_or_series(expected, index=index, dtype=float) result = df.rolling(window, center=True, closed=closed).sum() From f73a531638bf56a2ea500f37c8aaae52480ca0a8 Mon Sep 17 00:00:00 2001 From: Bert Palm Date: Sun, 10 Oct 2021 00:56:14 +0200 Subject: [PATCH 3/3] added whatsnew entry --- 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 e638a24f830ef..48fd388922a4b 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -503,6 +503,7 @@ Groupby/resample/rolling - 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`) +- Fixed bug in :meth:`Series.rolling` and :meth:`DataFrame.rolling` not respecting right bound on centered datetime-like windows, if the index contain duplicates (:issue:`#3944`) Reshaping ^^^^^^^^^