From 31fd2138bf1196b2783a93307e3b3038dc8685eb Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 2 Apr 2020 13:48:36 +0300 Subject: [PATCH 01/28] ENH: initial indexer implementation --- pandas/core/window/indexers.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index 921cdb3c2523f..e097f4824bdf0 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -120,3 +120,23 @@ def get_window_bounds( np.zeros(num_values, dtype=np.int64), np.arange(1, num_values + 1, dtype=np.int64), ) + + +class FixedForwardWindowIndexer(BaseIndexer): + """Calculate fixed forward-looking rolling window bounds,""" + + @Appender(get_window_bounds_doc) + def get_window_bounds( + self, + num_values: int = 0, + min_periods: Optional[int] = None, + center: Optional[bool] = None, + closed: Optional[str] = None, + ) -> Tuple[np.ndarray, np.ndarray]: + + start = np.arange(num_values, dtype="int64") + end_s = start[:-self.window_size] + self.window_size + end_e = np.full[self.window_size, num_values, dtype="int64"] + end = np.concatenate([end_s, end_e]) + + return start, end From d2b7743a289cdd0884976e02dda659a8aaf376c8 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 2 Apr 2020 13:52:09 +0300 Subject: [PATCH 02/28] FIX: fix brackets --- pandas/core/window/indexers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index e097f4824bdf0..5c287135dce1f 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -136,7 +136,7 @@ def get_window_bounds( start = np.arange(num_values, dtype="int64") end_s = start[:-self.window_size] + self.window_size - end_e = np.full[self.window_size, num_values, dtype="int64"] + end_e = np.full(self.window_size, num_values, dtype="int64") end = np.concatenate([end_s, end_e]) return start, end From 5afb0660c2b832b254759c44ac217a8e57699f89 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 2 Apr 2020 14:52:37 +0300 Subject: [PATCH 03/28] ENH: expose FixedForwardWIndowIndexer through API --- pandas/api/indexers/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/api/indexers/__init__.py b/pandas/api/indexers/__init__.py index 826297e6b498f..0b36b53675e23 100644 --- a/pandas/api/indexers/__init__.py +++ b/pandas/api/indexers/__init__.py @@ -3,6 +3,6 @@ """ from pandas.core.indexers import check_array_indexer -from pandas.core.window.indexers import BaseIndexer +from pandas.core.window.indexers import BaseIndexer, FixedForwardWindowIndexer -__all__ = ["check_array_indexer", "BaseIndexer"] +__all__ = ["check_array_indexer", "BaseIndexer", "FixedForwardWindowIndexer"] From 212448f1c74fc0b5a58d050b6b45b55a438f1460 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 2 Apr 2020 15:13:50 +0300 Subject: [PATCH 04/28] DOC: add whatsnew entry --- doc/source/whatsnew/v1.1.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 8bff34dbdadad..1982383c93116 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -104,6 +104,7 @@ Other API changes - ``loc`` lookups with an object-dtype :class:`Index` and an integer key will now raise ``KeyError`` instead of ``TypeError`` when key is missing (:issue:`31905`) - Using a :func:`pandas.api.indexers.BaseIndexer` with ``std``, ``var``, ``count``, ``skew``, ``cov``, ``corr`` will now raise a ``NotImplementedError`` (:issue:`32865`) - Using a :func:`pandas.api.indexers.BaseIndexer` with ``min``, ``max`` will now return correct results for any monotonic :func:`pandas.api.indexers.BaseIndexer` descendant (:issue:`32865`) +- Added a :func:`pandas.api.indexers.FixedForwardWindowIndexer` class to support forward-looking windows during ``rolling`` operations. - Backwards incompatible API changes From 0aa7980574ce3c41dbff682306278843b97ea704 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 2 Apr 2020 15:15:19 +0300 Subject: [PATCH 05/28] CLN: run black --- pandas/core/window/indexers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index 5c287135dce1f..ba2be077a9def 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -135,7 +135,7 @@ def get_window_bounds( ) -> Tuple[np.ndarray, np.ndarray]: start = np.arange(num_values, dtype="int64") - end_s = start[:-self.window_size] + self.window_size + end_s = start[: -self.window_size] + self.window_size end_e = np.full(self.window_size, num_values, dtype="int64") end = np.concatenate([end_s, end_e]) From fff110c7522d5e76831c5c1d08043d795752599a Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Thu, 2 Apr 2020 15:26:44 +0300 Subject: [PATCH 06/28] DOC: add example to Rolling docstring --- pandas/core/window/rolling.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index dc8cf839d0bcb..896bd326d0904 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -900,6 +900,17 @@ class Window(_Window): 3 2.0 4 4.0 + Same as above, but with forward-looking windows + + >>> indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=2) + >>> df.rolling(window=indexer, min_periods=1).sum() + B + 0 1.0 + 1 3.0 + 2 2.0 + 3 4.0 + 4 4.0 + A ragged (meaning not-a-regular frequency), time-indexed DataFrame >>> df = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]}, From c94cbd59368454826b23b4094ecd193fe69b0eb1 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sat, 4 Apr 2020 07:48:19 +0300 Subject: [PATCH 07/28] TST: use new class in test_rolling_forward_window --- pandas/tests/window/test_base_indexer.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/pandas/tests/window/test_base_indexer.py b/pandas/tests/window/test_base_indexer.py index 25d575e0ad0b6..80645b6786d28 100644 --- a/pandas/tests/window/test_base_indexer.py +++ b/pandas/tests/window/test_base_indexer.py @@ -3,7 +3,7 @@ from pandas import DataFrame, Series import pandas._testing as tm -from pandas.api.indexers import BaseIndexer +from pandas.api.indexers import BaseIndexer, FixedForwardWindowIndexer from pandas.core.window.indexers import ExpandingIndexer @@ -105,19 +105,10 @@ def get_window_bounds(self, num_values, min_periods, center, closed): ) def test_rolling_forward_window(constructor, func, alt_func, expected): # GH 32865 - class ForwardIndexer(BaseIndexer): - def get_window_bounds(self, num_values, min_periods, center, closed): - start = np.arange(num_values, dtype="int64") - end_s = start[: -self.window_size] + self.window_size - end_e = np.full(self.window_size, num_values, dtype="int64") - end = np.concatenate([end_s, end_e]) - - return start, end - values = np.arange(10) values[5] = 100.0 - indexer = ForwardIndexer(window_size=3) + indexer = FixedForwardWindowIndexer(window_size=3) rolling = constructor(values).rolling(window=indexer, min_periods=2) result = getattr(rolling, func)() expected = constructor(expected) From 4e5aa023c0783e2ed509296b04c49be250b99ded Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sat, 4 Apr 2020 08:05:59 +0300 Subject: [PATCH 08/28] TST: add benchmark --- asv_bench/benchmarks/rolling.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/asv_bench/benchmarks/rolling.py b/asv_bench/benchmarks/rolling.py index 5133bbd285b50..cda0c8985fbdc 100644 --- a/asv_bench/benchmarks/rolling.py +++ b/asv_bench/benchmarks/rolling.py @@ -165,4 +165,26 @@ def peakmem_fixed(self): self.roll.max() +class ForwardWindowMethods: + params = ( + ["DataFrame", "Series"], + [10, 1000], + ["int", "float"], + ["median", "mean", "max", "min", "kurt", "sum"], + ) + param_names = ["constructor", "window_size", "dtype", "method"] + + def setup(self): + N = 10 ** 5 + arr = np.random.random(N).astype(dtype) + indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size) + self.roll = getattr(pd, constructor)(arr).rolling(window=indexer) + + def time_rolling(self, constructor, window, dtype, method): + getattr(self.roll, method)() + + def peakmem_rolling(self, constructor, window, dtype, method): + getattr(self.roll, method)() + + from .pandas_vb_common import setup # noqa: F401 isort:skip From 271cc36900474bec7bae9af6f3a6f1e267e91d49 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sat, 4 Apr 2020 11:34:39 +0300 Subject: [PATCH 09/28] fix benchmark --- asv_bench/benchmarks/rolling.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/asv_bench/benchmarks/rolling.py b/asv_bench/benchmarks/rolling.py index cda0c8985fbdc..97222b3e59d11 100644 --- a/asv_bench/benchmarks/rolling.py +++ b/asv_bench/benchmarks/rolling.py @@ -174,16 +174,16 @@ class ForwardWindowMethods: ) param_names = ["constructor", "window_size", "dtype", "method"] - def setup(self): + def setup(self, constructor, window_size, dtype, method): N = 10 ** 5 arr = np.random.random(N).astype(dtype) indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size) self.roll = getattr(pd, constructor)(arr).rolling(window=indexer) - def time_rolling(self, constructor, window, dtype, method): + def time_rolling(self, constructor, window_size, dtype, method): getattr(self.roll, method)() - def peakmem_rolling(self, constructor, window, dtype, method): + def peakmem_rolling(self, constructor, window_size, dtype, method): getattr(self.roll, method)() From dc7fec844ebe8a00705c423003c0050f8ff73cbc Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sat, 4 Apr 2020 21:46:33 +0300 Subject: [PATCH 10/28] DOC: document the indexer in the user guide --- doc/source/user_guide/computation.rst | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 9951642ca98a4..d90733fdcaf8b 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -571,6 +571,27 @@ and we want to use an expanding window where ``use_expanding`` is ``True`` other 3 3.0 4 10.0 +For some problems, knowledge of the future is available for analysis. For example, this occurs when +each data point is a full time series read from an experiment, and the task is to extract underlying +conditions. In these cases, it can be useful to perform forward-looking rolling window computations. +For this purpose, ``FixedForwardWindowIndexer`` class is provided. This ``BaseIndexer`` subclass +implements a closed fixed-width forward-looking rolling window, and we can use it as follows: + +.. code-block:: ipython + + In [5]: from pandas.api.indexers import FixedForwardWindowIndexer + + In [6]: indexer = FixedForwardWindowIndexer(window_size=2) + + In [7]: df.rolling(indexer, min_periods=1).sum() + Out[8]: + values + 0 1.0 + 1 3.0 + 2 5.0 + 3 7.0 + 4 4.0 + .. _stats.rolling_window.endpoints: From e1a6f7383d6d5142e559f72896d1d0fcf8b1cede Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sat, 4 Apr 2020 21:48:29 +0300 Subject: [PATCH 11/28] DOC: edit the text in the user_guide --- doc/source/user_guide/computation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index d90733fdcaf8b..8803cbbc04611 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -571,10 +571,10 @@ and we want to use an expanding window where ``use_expanding`` is ``True`` other 3 3.0 4 10.0 -For some problems, knowledge of the future is available for analysis. For example, this occurs when +For some problems knowledge of the future is available for analysis. For example, this occurs when each data point is a full time series read from an experiment, and the task is to extract underlying -conditions. In these cases, it can be useful to perform forward-looking rolling window computations. -For this purpose, ``FixedForwardWindowIndexer`` class is provided. This ``BaseIndexer`` subclass +conditions. In these cases it can be useful to perform forward-looking rolling window computations. +``FixedForwardWindowIndexer`` class is available for this purpose. This ``BaseIndexer`` subclass implements a closed fixed-width forward-looking rolling window, and we can use it as follows: .. code-block:: ipython From dadcb3dea5548a5254fec9d63cad02c21a456661 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sat, 4 Apr 2020 23:55:42 +0300 Subject: [PATCH 12/28] fix the benchmark --- asv_bench/benchmarks/rolling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asv_bench/benchmarks/rolling.py b/asv_bench/benchmarks/rolling.py index 97222b3e59d11..f85dc83ab8605 100644 --- a/asv_bench/benchmarks/rolling.py +++ b/asv_bench/benchmarks/rolling.py @@ -177,7 +177,7 @@ class ForwardWindowMethods: def setup(self, constructor, window_size, dtype, method): N = 10 ** 5 arr = np.random.random(N).astype(dtype) - indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size) + indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=window_size) self.roll = getattr(pd, constructor)(arr).rolling(window=indexer) def time_rolling(self, constructor, window_size, dtype, method): From 46f45c2d3468ac91c2ff9a34dfe9b0ed6ddc8baf Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Sun, 5 Apr 2020 08:16:47 +0300 Subject: [PATCH 13/28] DOC: add versionadded to user_guide --- doc/source/user_guide/computation.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 8803cbbc04611..7eca7294afc1d 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -571,6 +571,8 @@ and we want to use an expanding window where ``use_expanding`` is ``True`` other 3 3.0 4 10.0 +.. versionadded:: 1.1 + For some problems knowledge of the future is available for analysis. For example, this occurs when each data point is a full time series read from an experiment, and the task is to extract underlying conditions. In these cases it can be useful to perform forward-looking rolling window computations. From 7464c923f98a89e887cb4f875ae2cfcfc00a9d19 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 07:48:30 +0300 Subject: [PATCH 14/28] raise if min_periods, center, or closed is not None --- pandas/core/window/indexers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index ba2be077a9def..b0d683e6fa85c 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -134,6 +134,9 @@ def get_window_bounds( closed: Optional[str] = None, ) -> Tuple[np.ndarray, np.ndarray]: + if min_periods is not None or center is not None or closed is not None: + raise ValueError("min_periods, center, and closed must all be None.") + start = np.arange(num_values, dtype="int64") end_s = start[: -self.window_size] + self.window_size end_e = np.full(self.window_size, num_values, dtype="int64") From 6cdd20d4fe53c24b09ab16d39d5000d98f00a7e3 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 09:48:48 +0300 Subject: [PATCH 15/28] DOC: expand the class docstring --- pandas/core/window/indexers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index b0d683e6fa85c..681d36fed2c51 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -123,7 +123,8 @@ def get_window_bounds( class FixedForwardWindowIndexer(BaseIndexer): - """Calculate fixed forward-looking rolling window bounds,""" + """Creates window boundaries for fixed-length windows that include the + current row.""" @Appender(get_window_bounds_doc) def get_window_bounds( From fb4338167b9e17ed8b0db5d5b5d67f55e1470a76 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 09:53:34 +0300 Subject: [PATCH 16/28] DOC: add examples to the class docstring --- pandas/core/window/indexers.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index 681d36fed2c51..7a8764d2d25d0 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -123,8 +123,30 @@ def get_window_bounds( class FixedForwardWindowIndexer(BaseIndexer): - """Creates window boundaries for fixed-length windows that include the - current row.""" + """ + Creates window boundaries for fixed-length windows that include the + current row. + + Examples + -------- + >>> df = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]}) + >>> df + B + 0 0.0 + 1 1.0 + 2 2.0 + 3 NaN + 4 4.0 + + >>> indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=2) + >>> df.rolling(window=indexer, min_periods=1).sum() + B + 0 1.0 + 1 3.0 + 2 2.0 + 3 4.0 + 4 4.0 + """ @Appender(get_window_bounds_doc) def get_window_bounds( From 97028399067df8bca99e60c29e6cd40fd5a1559a Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 11:24:12 +0300 Subject: [PATCH 17/28] DOC: add ref from whatsnew to the user guide --- doc/source/whatsnew/v1.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 1982383c93116..d1fa634a426b3 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -104,7 +104,7 @@ Other API changes - ``loc`` lookups with an object-dtype :class:`Index` and an integer key will now raise ``KeyError`` instead of ``TypeError`` when key is missing (:issue:`31905`) - Using a :func:`pandas.api.indexers.BaseIndexer` with ``std``, ``var``, ``count``, ``skew``, ``cov``, ``corr`` will now raise a ``NotImplementedError`` (:issue:`32865`) - Using a :func:`pandas.api.indexers.BaseIndexer` with ``min``, ``max`` will now return correct results for any monotonic :func:`pandas.api.indexers.BaseIndexer` descendant (:issue:`32865`) -- Added a :func:`pandas.api.indexers.FixedForwardWindowIndexer` class to support forward-looking windows during ``rolling`` operations. +- Added a :func:`pandas.api.indexers.FixedForwardWindowIndexer` class to support forward-looking windows during ``rolling`` operations. For more information on working with custom window indexers see :ref:`Custom window rolling subsection ` in the user guide. - Backwards incompatible API changes From 728ada2f95267530cee54ce77baf86c99b56c35c Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 12:40:44 +0300 Subject: [PATCH 18/28] rollback raising behavior --- pandas/core/window/indexers.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index 7a8764d2d25d0..92b4beeabbd95 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -157,9 +157,6 @@ def get_window_bounds( closed: Optional[str] = None, ) -> Tuple[np.ndarray, np.ndarray]: - if min_periods is not None or center is not None or closed is not None: - raise ValueError("min_periods, center, and closed must all be None.") - start = np.arange(num_values, dtype="int64") end_s = start[: -self.window_size] + self.window_size end_e = np.full(self.window_size, num_values, dtype="int64") From ffd50c52751ee7508f9991ae9b0c8404ced3d3c3 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 13:45:20 +0300 Subject: [PATCH 19/28] add errors for center and closed --- pandas/core/window/indexers.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index 92b4beeabbd95..6e926fc733593 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -157,6 +157,14 @@ def get_window_bounds( closed: Optional[str] = None, ) -> Tuple[np.ndarray, np.ndarray]: + if center: + raise ValueError("Forward-looking windows can't have center=True") + if closed is not None: + raise ValueError( + "Forward-looking windows don't support setting the closed" + "argument" + ) + start = np.arange(num_values, dtype="int64") end_s = start[: -self.window_size] + self.window_size end_e = np.full(self.window_size, num_values, dtype="int64") From 3ed043781beffc5232a6c2f0cdcd6bea79bc53fc Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 14:17:47 +0300 Subject: [PATCH 20/28] CLN: run black --- pandas/core/window/indexers.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index 6e926fc733593..de43128849ee8 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -161,8 +161,7 @@ def get_window_bounds( raise ValueError("Forward-looking windows can't have center=True") if closed is not None: raise ValueError( - "Forward-looking windows don't support setting the closed" - "argument" + "Forward-looking windows don't support setting the closed" "argument" ) start = np.arange(num_values, dtype="int64") From 1e3efddf1e63716e144f3a9d858e14a077faa844 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Mon, 6 Apr 2020 14:19:24 +0300 Subject: [PATCH 21/28] CLN: remove unnecessary quotes --- pandas/core/window/indexers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/window/indexers.py b/pandas/core/window/indexers.py index de43128849ee8..9a02c5231c151 100644 --- a/pandas/core/window/indexers.py +++ b/pandas/core/window/indexers.py @@ -161,7 +161,7 @@ def get_window_bounds( raise ValueError("Forward-looking windows can't have center=True") if closed is not None: raise ValueError( - "Forward-looking windows don't support setting the closed" "argument" + "Forward-looking windows don't support setting the closed argument" ) start = np.arange(num_values, dtype="int64") From 9bc5fc321f174f7c246863406c85bae82a7bc28b Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Tue, 7 Apr 2020 09:53:09 +0300 Subject: [PATCH 22/28] DOC: replace code-block with ipython block --- doc/source/user_guide/computation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 7eca7294afc1d..b026447b92020 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -541,7 +541,7 @@ For example, if we have the following ``DataFrame``: and we want to use an expanding window where ``use_expanding`` is ``True`` otherwise a window of size 1, we can create the following ``BaseIndexer``: -.. code-block:: ipython +.. ipython:: ipython In [2]: from pandas.api.indexers import BaseIndexer ...: From bd265f41e927f521759e2f09c727de3968dd06bd Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Tue, 7 Apr 2020 13:10:45 +0300 Subject: [PATCH 23/28] DOC: expose docstring, make links clickable --- doc/source/reference/window.rst | 11 +++++++++++ doc/source/user_guide/computation.rst | 23 ++++++++--------------- doc/source/whatsnew/v1.1.0.rst | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/doc/source/reference/window.rst b/doc/source/reference/window.rst index 570a0607ebd21..48d112c6cee55 100644 --- a/doc/source/reference/window.rst +++ b/doc/source/reference/window.rst @@ -85,3 +85,14 @@ Base class for defining custom window boundaries. :toctree: api/ api.indexers.BaseIndexer + +Forward-looking fixed window indexer +-------------- +.. currentmodule:: pandas + +Creates window boundaries for fixed-length windows that include the current row. + +.. autosummary:: + :toctree: api/ + + api.indexers.FixedForwardWindowIndexer diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index b026447b92020..a675197e62b95 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -541,7 +541,7 @@ For example, if we have the following ``DataFrame``: and we want to use an expanding window where ``use_expanding`` is ``True`` otherwise a window of size 1, we can create the following ``BaseIndexer``: -.. ipython:: ipython +.. code-block:: ipython In [2]: from pandas.api.indexers import BaseIndexer ...: @@ -576,23 +576,16 @@ and we want to use an expanding window where ``use_expanding`` is ``True`` other For some problems knowledge of the future is available for analysis. For example, this occurs when each data point is a full time series read from an experiment, and the task is to extract underlying conditions. In these cases it can be useful to perform forward-looking rolling window computations. -``FixedForwardWindowIndexer`` class is available for this purpose. This ``BaseIndexer`` subclass -implements a closed fixed-width forward-looking rolling window, and we can use it as follows: - -.. code-block:: ipython +:func:`FixedForwardWindowIndexer ` class is available for this purpose. +This :func:`BaseIndexer ` subclass implements a closed fixed-width +forward-looking rolling window, and we can use it as follows: - In [5]: from pandas.api.indexers import FixedForwardWindowIndexer +.. ipython:: ipython - In [6]: indexer = FixedForwardWindowIndexer(window_size=2) + from pandas.api.indexers import BaseIndexer, FixedForwardWindowIndexer - In [7]: df.rolling(indexer, min_periods=1).sum() - Out[8]: - values - 0 1.0 - 1 3.0 - 2 5.0 - 3 7.0 - 4 4.0 + indexer = FixedForwardWindowIndexer(window_size=2) + df.rolling(indexer, min_periods=1).sum() .. _stats.rolling_window.endpoints: diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 3f61a45c6716a..75da300a18f4d 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -104,7 +104,7 @@ Other API changes - ``loc`` lookups with an object-dtype :class:`Index` and an integer key will now raise ``KeyError`` instead of ``TypeError`` when key is missing (:issue:`31905`) - Using a :func:`pandas.api.indexers.BaseIndexer` with ``std``, ``var``, ``count``, ``skew``, ``cov``, ``corr`` will now raise a ``NotImplementedError`` (:issue:`32865`) - Using a :func:`pandas.api.indexers.BaseIndexer` with ``min``, ``max`` will now return correct results for any monotonic :func:`pandas.api.indexers.BaseIndexer` descendant (:issue:`32865`) -- Added a :func:`pandas.api.indexers.FixedForwardWindowIndexer` class to support forward-looking windows during ``rolling`` operations. For more information on working with custom window indexers see :ref:`Custom window rolling subsection ` in the user guide. +- Added a :func:`pandas.api.indexers.FixedForwardWindowIndexer` class to support forward-looking windows during ``rolling`` operations. - Backwards incompatible API changes From d08081b15820b27304c4142cb2d17f126adc684d Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Tue, 7 Apr 2020 13:15:57 +0300 Subject: [PATCH 24/28] TST: add error raising tests --- pandas/tests/window/test_base_indexer.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pandas/tests/window/test_base_indexer.py b/pandas/tests/window/test_base_indexer.py index 80645b6786d28..bb93c70b8a597 100644 --- a/pandas/tests/window/test_base_indexer.py +++ b/pandas/tests/window/test_base_indexer.py @@ -109,6 +109,17 @@ def test_rolling_forward_window(constructor, func, alt_func, expected): values[5] = 100.0 indexer = FixedForwardWindowIndexer(window_size=3) + + match = "Forward-looking windows can't have center=True" + with pytest.raises(ValueError, match=match): + rolling = constructor(values).rolling(window=indexer, center=True) + result = getattr(rolling, func)() + + match = "Forward-looking windows don't support setting the closed argument" + with pytest.raises(ValueError, match=match): + rolling = constructor(values).rolling(window=indexer, closed="right") + result = getattr(rolling, func)() + rolling = constructor(values).rolling(window=indexer, min_periods=2) result = getattr(rolling, func)() expected = constructor(expected) From 81c42161723250f36543433baeff6d921194e323 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Tue, 7 Apr 2020 15:28:56 +0300 Subject: [PATCH 25/28] CLN: clean up formatting in docs --- doc/source/reference/window.rst | 2 +- doc/source/user_guide/computation.rst | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/reference/window.rst b/doc/source/reference/window.rst index 48d112c6cee55..56819beaba4c7 100644 --- a/doc/source/reference/window.rst +++ b/doc/source/reference/window.rst @@ -87,7 +87,7 @@ Base class for defining custom window boundaries. api.indexers.BaseIndexer Forward-looking fixed window indexer --------------- +------------------------------------ .. currentmodule:: pandas Creates window boundaries for fixed-length windows that include the current row. diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 3e0b5c672cf6c..52b152c4480dd 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -583,7 +583,6 @@ forward-looking rolling window, and we can use it as follows: .. ipython:: ipython from pandas.api.indexers import BaseIndexer, FixedForwardWindowIndexer - indexer = FixedForwardWindowIndexer(window_size=2) df.rolling(indexer, min_periods=1).sum() From 1451340e1e15712b397b573be03ed80188166a5a Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Tue, 7 Apr 2020 15:53:08 +0300 Subject: [PATCH 26/28] CLN: remove unnecessary BaseIndexer import --- doc/source/user_guide/computation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 52b152c4480dd..5cf7253beb9c2 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -582,7 +582,7 @@ forward-looking rolling window, and we can use it as follows: .. ipython:: ipython - from pandas.api.indexers import BaseIndexer, FixedForwardWindowIndexer + from pandas.api.indexers import FixedForwardWindowIndexer indexer = FixedForwardWindowIndexer(window_size=2) df.rolling(indexer, min_periods=1).sum() From 768197a4445b549184e16df35b80d38f4afe610c Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Tue, 7 Apr 2020 17:21:38 +0300 Subject: [PATCH 27/28] CLN: remove unnecessary new line in computation.rst --- doc/source/user_guide/computation.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 5cf7253beb9c2..af2f02a09428b 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -586,7 +586,6 @@ forward-looking rolling window, and we can use it as follows: indexer = FixedForwardWindowIndexer(window_size=2) df.rolling(indexer, min_periods=1).sum() - .. _stats.rolling_window.endpoints: Rolling window endpoints From bc59bb79801bfcd456f011edbe813720f50e26b3 Mon Sep 17 00:00:00 2001 From: Alexander Kirko Date: Wed, 8 Apr 2020 08:07:10 +0300 Subject: [PATCH 28/28] DOC: move new indexer in window reference, delete extra --- doc/source/reference/window.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/doc/source/reference/window.rst b/doc/source/reference/window.rst index 56819beaba4c7..fb60a0d387ca2 100644 --- a/doc/source/reference/window.rst +++ b/doc/source/reference/window.rst @@ -85,14 +85,4 @@ Base class for defining custom window boundaries. :toctree: api/ api.indexers.BaseIndexer - -Forward-looking fixed window indexer ------------------------------------- -.. currentmodule:: pandas - -Creates window boundaries for fixed-length windows that include the current row. - -.. autosummary:: - :toctree: api/ - api.indexers.FixedForwardWindowIndexer