From 4081beb14acaa4ec2b62b115c724eacc6a48b64c Mon Sep 17 00:00:00 2001 From: Kernc Date: Tue, 6 Aug 2019 02:23:41 +0200 Subject: [PATCH 1/4] BUG: Fix windowing over read-only arrays --- doc/source/whatsnew/v0.25.1.rst | 1 + pandas/core/window.py | 7 +++++-- pandas/tests/window/test_rolling.py | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.25.1.rst b/doc/source/whatsnew/v0.25.1.rst index 943a6adb7944e..66b760a76dad3 100644 --- a/doc/source/whatsnew/v0.25.1.rst +++ b/doc/source/whatsnew/v0.25.1.rst @@ -118,6 +118,7 @@ Groupby/resample/rolling ^^^^^^^^^^^^^^^^^^^^^^^^ - Bug in :meth:`pandas.core.groupby.DataFrameGroupBy.transform` where applying a timezone conversion lambda function would drop timezone information (:issue:`27496`) +- Bug in windowing over read-only arrays (:issue:`27766`) - - diff --git a/pandas/core/window.py b/pandas/core/window.py index a7425bc1466c3..69d832c7c9a42 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -246,8 +246,11 @@ def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: except (ValueError, TypeError): raise TypeError("cannot handle this type -> {0}".format(values.dtype)) - # Always convert inf to nan - values[np.isinf(values)] = np.NaN + # Convert inf to nan for C funcs + inf = np.isinf(values) + if inf.any(): + values = values.copy() # GH-27766, Don't write into user's data + values[inf] = np.nan return values diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index c7177e1d3914f..dc532a988ef15 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -326,3 +326,10 @@ def test_rolling_axis_count(self, axis_frame): result = df.rolling(2, axis=axis_frame).count() tm.assert_frame_equal(result, expected) + + def test_readonly_array(self): + arr = np.array([1, 3, np.nan, 3, 5]) + arr.setflags(write=False) + tm.assert_series_equal( + pd.Series(arr).rolling(2).mean(), pd.Series([np.nan, 2, np.nan, np.nan, 4]) + ) From 0fc1d55db92e69fdb633ddc0b4098d897b447bf6 Mon Sep 17 00:00:00 2001 From: Kernc Date: Tue, 6 Aug 2019 03:15:35 +0200 Subject: [PATCH 2/4] comment on previous line --- pandas/core/window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/window.py b/pandas/core/window.py index 69d832c7c9a42..c18c3a272bb71 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -249,8 +249,8 @@ def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: # Convert inf to nan for C funcs inf = np.isinf(values) if inf.any(): - values = values.copy() # GH-27766, Don't write into user's data - values[inf] = np.nan + # GH-27766, Don't write into user's data + values = np.where(inf, np.nan, values) return values From bdb0ca50bbb0c5b720ac9064b25c8e68c99c72fb Mon Sep 17 00:00:00 2001 From: Kernc Date: Tue, 6 Aug 2019 03:26:39 +0200 Subject: [PATCH 3/4] strip comment now that np.where is used --- pandas/core/window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/window.py b/pandas/core/window.py index c18c3a272bb71..3e3f17369db7b 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -249,7 +249,6 @@ def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: # Convert inf to nan for C funcs inf = np.isinf(values) if inf.any(): - # GH-27766, Don't write into user's data values = np.where(inf, np.nan, values) return values From 56d9ba679c7b251bc99d8c3a3a479d25da852aa5 Mon Sep 17 00:00:00 2001 From: Kernc Date: Tue, 6 Aug 2019 10:34:18 +0200 Subject: [PATCH 4/4] link issue, revise --- pandas/tests/window/test_rolling.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index dc532a988ef15..f0787ab3d191f 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -328,8 +328,9 @@ def test_rolling_axis_count(self, axis_frame): tm.assert_frame_equal(result, expected) def test_readonly_array(self): + # GH-27766 arr = np.array([1, 3, np.nan, 3, 5]) arr.setflags(write=False) - tm.assert_series_equal( - pd.Series(arr).rolling(2).mean(), pd.Series([np.nan, 2, np.nan, np.nan, 4]) - ) + result = pd.Series(arr).rolling(2).mean() + expected = pd.Series([np.nan, 2, np.nan, np.nan, 4]) + tm.assert_series_equal(result, expected)