From 78a2d1fbb1ab386d2d87af7d0f10b7041f999264 Mon Sep 17 00:00:00 2001 From: ihsan Date: Sun, 30 Jun 2019 16:05:45 +0300 Subject: [PATCH 1/5] Fix empty variable window issue with rolling min max --- pandas/_libs/window.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/window.pyx b/pandas/_libs/window.pyx index df86f395d6097..6203577e450d9 100644 --- a/pandas/_libs/window.pyx +++ b/pandas/_libs/window.pyx @@ -1313,9 +1313,11 @@ cdef _roll_min_max_variable(ndarray[numeric] values, # if right is open then the first window is empty close_offset = 0 if endi[0] > starti[0] else 1 + # first window's size + curr_win_size = endi[0] - starti[0] for i in range(endi[0], endi[N-1]): - if not Q.empty(): + if not Q.empty() and curr_win_size > 0: output[i-1+close_offset] = calc_mm( minp, nobs, values[Q.front()]) else: @@ -1344,7 +1346,7 @@ cdef _roll_min_max_variable(ndarray[numeric] values, Q.push_back(i) W.push_back(i) - if not Q.empty(): + if not Q.empty() and curr_win_size > 0: output[N-1] = calc_mm(minp, nobs, values[Q.front()]) else: output[N-1] = NaN From 9c4966059540b05b308c7f3542a7b60dcc890af9 Mon Sep 17 00:00:00 2001 From: ihsan Date: Sun, 30 Jun 2019 16:06:47 +0300 Subject: [PATCH 2/5] Test empty closed window --- pandas/tests/test_window.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/pandas/tests/test_window.py b/pandas/tests/test_window.py index 4dfdd1c96728b..639d5bcfefa3f 100644 --- a/pandas/tests/test_window.py +++ b/pandas/tests/test_window.py @@ -520,6 +520,19 @@ def test_closed(self): with pytest.raises(ValueError): df.rolling(window=3, closed='neither') + @pytest.mark.parametrize("closed", ["neither", "left"]) + @pytest.mark.parametrize( + "func", ["std", "mean", "median", "sum", "max", "min", "var"]) + def test_closed_empty(self, closed, func): + # GH 26005 + ser = pd.Series(data=np.arange(5), + index=pd.date_range("2000", periods=5, freq="2D")) + roll = ser.rolling("1D", closed=closed) + + result = getattr(roll, func)() + expected = pd.Series([np.nan] * 5, index=ser.index) + tm.assert_series_equal(result, expected) + @pytest.mark.parametrize("func", ['min', 'max']) def test_closed_one_entry(self, func): # GH24718 From 3b2f8d4583826d4da655e5de2c651be0ae4dbcdd Mon Sep 17 00:00:00 2001 From: ihsan Date: Sun, 30 Jun 2019 16:10:29 +0300 Subject: [PATCH 3/5] Add whatsnew --- doc/source/whatsnew/v0.25.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 82e093bc2bd49..e2554b0da148d 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -841,6 +841,7 @@ Groupby/resample/rolling - Bug in :meth:`pandas.core.groupby.GroupBy.agg` where incorrect results are returned for uint64 columns. (:issue:`26310`) - Bug in :meth:`pandas.core.window.Rolling.median` and :meth:`pandas.core.window.Rolling.quantile` where MemoryError is raised with empty window (:issue:`26005`) - Bug in :meth:`pandas.core.window.Rolling.median` and :meth:`pandas.core.window.Rolling.quantile` where incorrect results are returned with ``closed='left'`` and ``closed='neither'`` (:issue:`26005`) +- Bug in :meth:`pandas.core.window.Rolling.max` and :meth:`pandas.core.window.Rolling.min` where incorrect results are returned with an empty variable window`` (:issue:`26005`) Reshaping ^^^^^^^^^ From d9adc042add47dede717f9cdabc22aec9e2f1ea6 Mon Sep 17 00:00:00 2001 From: ihsan Date: Sun, 30 Jun 2019 16:58:06 +0300 Subject: [PATCH 4/5] Add kurt and skew to the list of tested functions --- pandas/tests/test_window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/test_window.py b/pandas/tests/test_window.py index 639d5bcfefa3f..2e8dc3297f6ce 100644 --- a/pandas/tests/test_window.py +++ b/pandas/tests/test_window.py @@ -521,8 +521,8 @@ def test_closed(self): df.rolling(window=3, closed='neither') @pytest.mark.parametrize("closed", ["neither", "left"]) - @pytest.mark.parametrize( - "func", ["std", "mean", "median", "sum", "max", "min", "var"]) + @pytest.mark.parametrize("func", ["var", "std", "mean", "median", "sum", + "max", "min", "kurt", "skew"]) def test_closed_empty(self, closed, func): # GH 26005 ser = pd.Series(data=np.arange(5), From 8e9d3906666fd968646410480e44f6efe0de6a02 Mon Sep 17 00:00:00 2001 From: ihsan Date: Sun, 30 Jun 2019 18:50:36 +0300 Subject: [PATCH 5/5] Use fixture --- pandas/tests/test_window.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pandas/tests/test_window.py b/pandas/tests/test_window.py index 2e8dc3297f6ce..defa4104b370f 100644 --- a/pandas/tests/test_window.py +++ b/pandas/tests/test_window.py @@ -48,6 +48,12 @@ def win_types_special(request): return request.param +@pytest.fixture(params=["sum", "mean", "median", "max", "min", + "var", "std", "kurt", "skew"]) +def arithmetic_win_operators(request): + return request.param + + class Base: _nan_locs = np.arange(20, 40) @@ -521,15 +527,14 @@ def test_closed(self): df.rolling(window=3, closed='neither') @pytest.mark.parametrize("closed", ["neither", "left"]) - @pytest.mark.parametrize("func", ["var", "std", "mean", "median", "sum", - "max", "min", "kurt", "skew"]) - def test_closed_empty(self, closed, func): + def test_closed_empty(self, closed, arithmetic_win_operators): # GH 26005 + func_name = arithmetic_win_operators ser = pd.Series(data=np.arange(5), index=pd.date_range("2000", periods=5, freq="2D")) roll = ser.rolling("1D", closed=closed) - result = getattr(roll, func)() + result = getattr(roll, func_name)() expected = pd.Series([np.nan] * 5, index=ser.index) tm.assert_series_equal(result, expected)