From 296473aa490c6316f583c575f40fae5e8916ff01 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Sun, 7 Mar 2021 16:37:23 -0800 Subject: [PATCH 1/3] CLN: Window code --- pandas/core/window/ewm.py | 6 +++--- pandas/core/window/rolling.py | 31 ++++++++++++------------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/pandas/core/window/ewm.py b/pandas/core/window/ewm.py index 5a71db82f26e4..6310a751492da 100644 --- a/pandas/core/window/ewm.py +++ b/pandas/core/window/ewm.py @@ -255,13 +255,13 @@ def __init__( self.ignore_na = ignore_na self.times = times if self.times is not None: - if isinstance(times, str): - self.times = self._selected_obj[times] + if isinstance(self.times, str): + self.times = self._selected_obj[self.times] if not is_datetime64_ns_dtype(self.times): raise ValueError("times must be datetime64[ns] dtype.") if len(self.times) != len(obj): raise ValueError("times must be the same length as the object.") - if not isinstance(halflife, (str, datetime.timedelta)): + if not isinstance(self.halflife, (str, datetime.timedelta)): raise ValueError( "halflife must be a string or datetime.timedelta object" ) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 299e1755c0025..37e81ffe1f7bc 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -64,7 +64,6 @@ SelectionMixin, ) import pandas.core.common as common -from pandas.core.construction import extract_array from pandas.core.indexes.api import ( Index, MultiIndex, @@ -301,11 +300,8 @@ def __iter__(self): result = obj.iloc[slice(s, e)] yield result - def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: + def _prep_values(self, values: ArrayLike) -> np.ndarray: """Convert input to numpy arrays for Cython routines""" - if values is None: - values = extract_array(self._selected_obj, extract_numpy=True) - if needs_i8_conversion(values.dtype): raise NotImplementedError( f"ops for {type(self).__name__} for this " @@ -351,6 +347,15 @@ def _insert_on_column(self, result: DataFrame, obj: DataFrame): # insert at the end result[name] = extra_col + def _resolve_output(self, out: DataFrame, obj: DataFrame) -> DataFrame: + if out.shape[1] == 0 and obj.shape[1] > 0: + raise DataError("No numeric types to aggregate") + elif out.shape[1] == 0: + return obj.astype("float64") + + self._insert_on_column(out, obj) + return out + @property def _index_array(self): # TODO: why do we get here with e.g. MultiIndex? @@ -421,13 +426,7 @@ def hfunc2d(values: ArrayLike) -> ArrayLike: new_mgr = mgr.apply(hfunc, ignore_failures=True) out = obj._constructor(new_mgr) - if out.shape[1] == 0 and obj.shape[1] > 0: - raise DataError("No numeric types to aggregate") - elif out.shape[1] == 0: - return obj.astype("float64") - - self._insert_on_column(out, obj) - return out + return self._resolve_output(out, obj) def _apply_tablewise( self, homogeneous_func: Callable[..., ArrayLike], name: Optional[str] = None @@ -444,13 +443,7 @@ def _apply_tablewise( result = result.T if self.axis == 1 else result out = obj._constructor(result, index=obj.index, columns=obj.columns) - if out.shape[1] == 0 and obj.shape[1] > 0: - raise DataError("No numeric types to aggregate") - elif out.shape[1] == 0: - return obj.astype("float64") - - self._insert_on_column(out, obj) - return out + return self._resolve_output(out, obj) def _apply_pairwise( self, From 6c584d322e6c77764d964b9cc63048353a18baea Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Sun, 7 Mar 2021 17:34:15 -0800 Subject: [PATCH 2/3] Simplify argument --- pandas/core/window/rolling.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 37e81ffe1f7bc..c3c634271ff90 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -348,6 +348,7 @@ def _insert_on_column(self, result: DataFrame, obj: DataFrame): result[name] = extra_col def _resolve_output(self, out: DataFrame, obj: DataFrame) -> DataFrame: + """Validate and finalize result.""" if out.shape[1] == 0 and obj.shape[1] > 0: raise DataError("No numeric types to aggregate") elif out.shape[1] == 0: @@ -356,13 +357,6 @@ def _resolve_output(self, out: DataFrame, obj: DataFrame) -> DataFrame: self._insert_on_column(out, obj) return out - @property - def _index_array(self): - # TODO: why do we get here with e.g. MultiIndex? - if needs_i8_conversion(self._on.dtype): - return self._on.asi8 - return None - def _get_window_indexer(self) -> BaseIndexer: """ Return an indexer class that will compute the window start and end bounds @@ -371,7 +365,7 @@ def _get_window_indexer(self) -> BaseIndexer: return self.window if self._win_freq_i8 is not None: return VariableWindowIndexer( - index_array=self._index_array, window_size=self._win_freq_i8 + index_array=self._on.asi8, window_size=self._win_freq_i8 ) return FixedWindowIndexer(window_size=self.window) @@ -2195,8 +2189,7 @@ def _get_window_indexer(self) -> GroupbyIndexer: """ rolling_indexer: Type[BaseIndexer] indexer_kwargs: Optional[Dict[str, Any]] = None - index_array = self._index_array - window = self.window + index_array = self._on.asi8 if isinstance(self.window, BaseIndexer): rolling_indexer = type(self.window) indexer_kwargs = self.window.__dict__ @@ -2209,7 +2202,7 @@ def _get_window_indexer(self) -> GroupbyIndexer: window = self._win_freq_i8 else: rolling_indexer = FixedWindowIndexer - index_array = None + window = self.window window_indexer = GroupbyIndexer( index_array=index_array, window_size=window, From 3bb9f200bac19213fe4d216a5ab35ebe8e8e2c00 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke Date: Sun, 7 Mar 2021 18:52:10 -0800 Subject: [PATCH 3/3] Add back index array property --- pandas/core/window/rolling.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index c3c634271ff90..503849bf673d5 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -347,6 +347,13 @@ def _insert_on_column(self, result: DataFrame, obj: DataFrame): # insert at the end result[name] = extra_col + @property + def _index_array(self): + # TODO: why do we get here with e.g. MultiIndex? + if needs_i8_conversion(self._on.dtype): + return self._on.asi8 + return None + def _resolve_output(self, out: DataFrame, obj: DataFrame) -> DataFrame: """Validate and finalize result.""" if out.shape[1] == 0 and obj.shape[1] > 0: @@ -365,7 +372,7 @@ def _get_window_indexer(self) -> BaseIndexer: return self.window if self._win_freq_i8 is not None: return VariableWindowIndexer( - index_array=self._on.asi8, window_size=self._win_freq_i8 + index_array=self._index_array, window_size=self._win_freq_i8 ) return FixedWindowIndexer(window_size=self.window) @@ -2189,7 +2196,7 @@ def _get_window_indexer(self) -> GroupbyIndexer: """ rolling_indexer: Type[BaseIndexer] indexer_kwargs: Optional[Dict[str, Any]] = None - index_array = self._on.asi8 + index_array = self._index_array if isinstance(self.window, BaseIndexer): rolling_indexer = type(self.window) indexer_kwargs = self.window.__dict__