From 7e461a18d9f6928132afec6f48ce968b3e989ba6 Mon Sep 17 00:00:00 2001 From: Kaiqi Dong Date: Mon, 3 Dec 2018 17:43:52 +0100 Subject: [PATCH 01/18] remove \n from docstring --- pandas/core/arrays/datetimes.py | 26 +++++++++++++------------- pandas/core/arrays/timedeltas.py | 16 ++++++++-------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index cfe3afcf3730a..b3df505d56d78 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -82,7 +82,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = docstring + f.__doc__ = "\n{}\n".format(docstring) return property(f) @@ -1072,19 +1072,19 @@ def date(self): return tslib.ints_to_pydatetime(timestamps, box="date") - year = _field_accessor('year', 'Y', "\n The year of the datetime\n") + year = _field_accessor('year', 'Y', "The year of the datetime") month = _field_accessor('month', 'M', - "\n The month as January=1, December=12 \n") - day = _field_accessor('day', 'D', "\nThe days of the datetime\n") - hour = _field_accessor('hour', 'h', "\nThe hours of the datetime\n") - minute = _field_accessor('minute', 'm', "\nThe minutes of the datetime\n") - second = _field_accessor('second', 's', "\nThe seconds of the datetime\n") + "The month as January=1, December=12") + day = _field_accessor('day', 'D', "The days of the datetime") + hour = _field_accessor('hour', 'h', "The hours of the datetime") + minute = _field_accessor('minute', 'm', "The minutes of the datetime") + second = _field_accessor('second', 's', "The seconds of the datetime") microsecond = _field_accessor('microsecond', 'us', - "\nThe microseconds of the datetime\n") + "The microseconds of the datetime") nanosecond = _field_accessor('nanosecond', 'ns', - "\nThe nanoseconds of the datetime\n") + "The nanoseconds of the datetime") weekofyear = _field_accessor('weekofyear', 'woy', - "\nThe week ordinal of the year\n") + "The week ordinal of the year") week = weekofyear _dayofweek_doc = """ The day of the week with Monday=0, Sunday=6. @@ -1129,12 +1129,12 @@ def date(self): "The name of day in a week (ex: Friday)\n\n.. deprecated:: 0.23.0") dayofyear = _field_accessor('dayofyear', 'doy', - "\nThe ordinal day of the year\n") - quarter = _field_accessor('quarter', 'q', "\nThe quarter of the date\n") + "The ordinal day of the year") + quarter = _field_accessor('quarter', 'q', "The quarter of the date") days_in_month = _field_accessor( 'days_in_month', 'dim', - "\nThe number of days in the month\n") + "The number of days in the month") daysinmonth = days_in_month _is_month_doc = """ Indicates whether the date is the {first_or_last} day of the month. diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py index 830283d31a929..4afc9f5483c2a 100644 --- a/pandas/core/arrays/timedeltas.py +++ b/pandas/core/arrays/timedeltas.py @@ -59,7 +59,7 @@ def f(self): return result f.__name__ = name - f.__doc__ = docstring + f.__doc__ = "\n{}\n".format(docstring) return property(f) @@ -684,16 +684,16 @@ def to_pytimedelta(self): return tslibs.ints_to_pytimedelta(self.asi8) days = _field_accessor("days", "days", - "\nNumber of days for each element.\n") + "Number of days for each element.") seconds = _field_accessor("seconds", "seconds", - "\nNumber of seconds (>= 0 and less than 1 day) " - "for each element.\n") + "Number of seconds (>= 0 and less than 1 day) " + "for each element.") microseconds = _field_accessor("microseconds", "microseconds", - "\nNumber of microseconds (>= 0 and less " - "than 1 second) for each element.\n") + "Number of microseconds (>= 0 and less " + "than 1 second) for each element.") nanoseconds = _field_accessor("nanoseconds", "nanoseconds", - "\nNumber of nanoseconds (>= 0 and less " - "than 1 microsecond) for each element.\n") + "Number of nanoseconds (>= 0 and less " + "than 1 microsecond) for each element.") @property def components(self): From dea38f24c0067ae3fe9484b837c9649714213bba Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:26:31 +0100 Subject: [PATCH 02/18] fix issue 17038 --- pandas/core/reshape/pivot.py | 4 +++- pandas/tests/reshape/test_pivot.py | 20 ++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index b443ba142369c..9743d90f4dd04 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -117,7 +117,9 @@ def pivot_table( agged[v] = maybe_downcast_to_dtype(agged[v], data[v].dtype) table = agged - if table.index.nlevels > 1: + + # GH 17038, this check should only happen if index is specified + if table.index.nlevels > 1 and index: # Related GH #17123 # If index_names are integers, determine whether the integers refer # to the level position or name. diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 743fc50c87e96..46a05123c9fdd 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -896,12 +896,6 @@ def _check_output( totals = table.loc[("All", ""), value_col] assert totals == self.data[value_col].mean() - # no rows - rtable = self.data.pivot_table( - columns=["AA", "BB"], margins=True, aggfunc=np.mean - ) - assert isinstance(rtable, Series) - table = self.data.pivot_table(index=["AA", "BB"], margins=True, aggfunc="mean") for item in ["DD", "EE", "FF"]: totals = table.loc[("All", ""), item] @@ -972,6 +966,20 @@ def test_pivot_integer_columns(self): tm.assert_frame_equal(table, table2, check_names=False) + @pytest.mark.parametrize("cols", [(1, 2), ("a", "b"), (1, "b"), ("a", 1)]) + def test_pivot_table_multiindex_only(self, cols): + # GH 17038 + df2 = DataFrame({cols[0]: [1, 2, 3], cols[1]: [1, 2, 3], "v": [4, 5, 6]}) + + result = df2.pivot_table(values="v", columns=cols) + expected = DataFrame( + [[4, 5, 6]], + columns=MultiIndex.from_tuples([(1, 1), (2, 2), (3, 3)], names=cols), + index=Index(["v"]), + ) + + tm.assert_frame_equal(result, expected) + def test_pivot_no_level_overlap(self): # GH #1181 From cd9e7ac3f31ffaf95cd628863df911dea9fa1248 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:29:43 +0100 Subject: [PATCH 03/18] revert change --- pandas/core/reshape/pivot.py | 3 +-- pandas/tests/reshape/test_pivot.py | 20 ++++++-------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index 9743d90f4dd04..a7cdbb0da7a4e 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -118,8 +118,7 @@ def pivot_table( table = agged - # GH 17038, this check should only happen if index is specified - if table.index.nlevels > 1 and index: + if table.index.nlevels > 1: # Related GH #17123 # If index_names are integers, determine whether the integers refer # to the level position or name. diff --git a/pandas/tests/reshape/test_pivot.py b/pandas/tests/reshape/test_pivot.py index 46a05123c9fdd..743fc50c87e96 100644 --- a/pandas/tests/reshape/test_pivot.py +++ b/pandas/tests/reshape/test_pivot.py @@ -896,6 +896,12 @@ def _check_output( totals = table.loc[("All", ""), value_col] assert totals == self.data[value_col].mean() + # no rows + rtable = self.data.pivot_table( + columns=["AA", "BB"], margins=True, aggfunc=np.mean + ) + assert isinstance(rtable, Series) + table = self.data.pivot_table(index=["AA", "BB"], margins=True, aggfunc="mean") for item in ["DD", "EE", "FF"]: totals = table.loc[("All", ""), item] @@ -966,20 +972,6 @@ def test_pivot_integer_columns(self): tm.assert_frame_equal(table, table2, check_names=False) - @pytest.mark.parametrize("cols", [(1, 2), ("a", "b"), (1, "b"), ("a", 1)]) - def test_pivot_table_multiindex_only(self, cols): - # GH 17038 - df2 = DataFrame({cols[0]: [1, 2, 3], cols[1]: [1, 2, 3], "v": [4, 5, 6]}) - - result = df2.pivot_table(values="v", columns=cols) - expected = DataFrame( - [[4, 5, 6]], - columns=MultiIndex.from_tuples([(1, 1), (2, 2), (3, 3)], names=cols), - index=Index(["v"]), - ) - - tm.assert_frame_equal(result, expected) - def test_pivot_no_level_overlap(self): # GH #1181 From e5e912be0f596943067a7df812442764d311a086 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Tue, 14 Jan 2020 21:30:16 +0100 Subject: [PATCH 04/18] revert change --- pandas/core/reshape/pivot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/core/reshape/pivot.py b/pandas/core/reshape/pivot.py index a7cdbb0da7a4e..b443ba142369c 100644 --- a/pandas/core/reshape/pivot.py +++ b/pandas/core/reshape/pivot.py @@ -117,7 +117,6 @@ def pivot_table( agged[v] = maybe_downcast_to_dtype(agged[v], data[v].dtype) table = agged - if table.index.nlevels > 1: # Related GH #17123 # If index_names are integers, determine whether the integers refer From 4d85ab97f206fda8d57b0b3e5167b1c57e294100 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Fri, 15 May 2020 23:29:33 +0200 Subject: [PATCH 05/18] add iter for window --- pandas/core/window/rolling.py | 29 ++++- pandas/tests/window/test_expanding.py | 83 ++++++++++++-- pandas/tests/window/test_rolling.py | 153 +++++++++++++++++++++++--- 3 files changed, 241 insertions(+), 24 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 660fca61fd21c..9596a0e21dc33 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -247,8 +247,33 @@ def __repr__(self) -> str: return f"{self._window_type} [{attrs}]" def __iter__(self): - url = "https://github.com/pandas-dev/pandas/issues/11704" - raise NotImplementedError(f"See issue #11704 {url}") + window = self._get_window(win_type=None) + + blocks, obj = self._create_blocks() + block_list = list(blocks) + index = self._get_window_indexer(window=window) + + # Choose the min between min_periods and window to determine the output size + if self.min_periods is None: + iter_threshold = window + else: + iter_threshold = min(window, self.min_periods) + + for block in block_list: + start, end = index.get_window_bounds( + num_values=len(block), + min_periods=self.min_periods, + center=self.center, + closed=self.closed, + ) + # From get_window_bounds, those two should be equal in length of array + assert len(start) == len(end) + + window_size = len(start) + for i in range(window_size): + result = block.iloc[slice(start[i], end[i])] + if result.count().min() >= iter_threshold: + yield result def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: """Convert input to numpy arrays for Cython routines""" diff --git a/pandas/tests/window/test_expanding.py b/pandas/tests/window/test_expanding.py index aaa7e9a34fadf..c156cc856eced 100644 --- a/pandas/tests/window/test_expanding.py +++ b/pandas/tests/window/test_expanding.py @@ -88,15 +88,6 @@ def test_missing_minp_zero(): tm.assert_series_equal(result, expected) -@pytest.mark.parametrize("klass", [pd.Series, pd.DataFrame]) -def test_iter_raises(klass): - # https://github.com/pandas-dev/pandas/issues/11704 - # Iteration over a Window - obj = klass([1, 2, 3, 4]) - with pytest.raises(NotImplementedError): - iter(obj.expanding(2)) - - def test_expanding_axis(axis_frame): # see gh-23372. df = DataFrame(np.ones((10, 20))) @@ -131,3 +122,77 @@ def test_expanding_count_default_min_periods_with_null_values(constructor): result = constructor(values).expanding().count() expected = constructor(expected_counts) tm.assert_equal(result, expected) + + +@pytest.mark.parametrize( + "df,expected,min_periods", + [ + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2])], + 3, + ), + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [ + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2]), + ], + 2, + ), + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2]), + ], + 1, + ), + (DataFrame({"A": [1], "B": [4]}), [], 2), + (DataFrame(), [({}, [])], 1), + ( + DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), + [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2])], + 3, + ), + ( + DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), + [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]),], + 2, + ), + ( + DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), + [ + ({"A": [1, np.nan], "B": [np.nan, 5]}, [0, 1]), + ({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), + ], + 1, + ), + ], +) +def test_iter_expanding_dataframe(df, expected, min_periods): + # GH 11704 + expected = [DataFrame(values, index=index) for (values, index) in expected] + + for (expected, actual) in zip(expected, df.expanding(min_periods)): + tm.assert_frame_equal(actual, expected) + + +@pytest.mark.parametrize( + "ser,expected,min_periods", + [ + (Series([1, 2, 3]), [([1, 2, 3], [0, 1, 2])], 3), + (Series([1, 2, 3]), [([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], 2), + (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], 1), + (Series([1, 2]), [([1, 2], [0, 1])], 2), + (Series([np.nan, 2]), [([np.nan, 2], [0, np.nan])], 2), + (Series([], dtype="int64"), [], 2), + ], +) +def test_iter_expanding_series(ser, expected, min_periods): + # GH 11704 + expected = [Series(values, index=index) for (values, index) in expected] + + for (expected, actual) in zip(expected, ser.expanding(min_periods)): + tm.assert_series_equal(actual, expected) diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index a7582a86c0848..0414309101a22 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -7,7 +7,7 @@ import pandas.util._test_decorators as td import pandas as pd -from pandas import DataFrame, Series +from pandas import DataFrame, Series, date_range import pandas._testing as tm from pandas.core.window import Rolling @@ -310,18 +310,6 @@ def test_multi_index_names(): assert result.index.names == [None, "1", "2"] -@pytest.mark.parametrize("klass", [pd.Series, pd.DataFrame]) -def test_iter_raises(klass): - # https://github.com/pandas-dev/pandas/issues/11704 - # Iteration over a Window - obj = klass([1, 2, 3, 4]) - - msg = "See issue #11704 https://github.com/pandas-dev/pandas/issues/11704" - - with pytest.raises(NotImplementedError, match=msg): - iter(obj.rolling(2)) - - def test_rolling_axis_sum(axis_frame): # see gh-23372. df = DataFrame(np.ones((10, 20))) @@ -470,3 +458,142 @@ def test_rolling_count_default_min_periods_with_null_values(constructor): result = constructor(values).rolling(3).count() expected = constructor(expected_counts) tm.assert_equal(result, expected) + + +@pytest.mark.parametrize( + "df,expected,window,min_periods", + [ + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2])], + 3, + None, + ), + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [ + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [2, 3], "B": [5, 6]}, [1, 2]), + ], + 2, + 1, + ), + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [ + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [2, 3], "B": [5, 6]}, [1, 2]), + ], + 2, + 3, + ), + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [2], "B": [5]}, [1]), + ({"A": [3], "B": [6]}, [2]), + ], + 1, + 1, + ), + (DataFrame({"A": [1], "B": [4]}), [], 2, None), + (DataFrame({"A": [1], "B": [4]}), [], 2, 1), + (DataFrame(), [({}, [])], 2, None), + (DataFrame(), [({}, [])], 1, 2), + ( + DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), + [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2])], + 3, + 2, + ), + ], +) +def test_iter_rolling_dataframe(df, expected, window, min_periods): + # GH 11704 + expected = [DataFrame(values, index=index) for (values, index) in expected] + + for (expected, actual) in zip( + expected, df.rolling(window, min_periods=min_periods) + ): + print(expected) + print(actual) + tm.assert_frame_equal(actual, expected) + + +@pytest.mark.parametrize( + "ser,expected,window, min_periods", + [ + (Series([1, 2, 3]), [([1, 2, 3], [0, 1, 2])], 3, None), + (Series([1, 2, 3]), [([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 1), + (Series([1, 2, 3]), [([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 3), + (Series([1, 2, 3]), [([1], [0]), ([2], [1]), ([3], [2])], 1, 0), + (Series([1, 2, 3]), [([1], [0]), ([2], [1]), ([3], [2])], 1, 2), + (Series([1, 2]), [([1, 2], [0, 1])], 2, 0), + (Series([1, 2]), [([1, 2], [0, 1])], 2, 3), + (Series([], dtype="int64"), [], 2, 1), + (Series([], dtype="int64"), [], 2, 3), + ], +) +def test_iter_rolling_series(ser, expected, window, min_periods): + # GH 11704 + expected = [Series(values, index=index) for (values, index) in expected] + + for (expected, actual) in zip( + expected, ser.rolling(window, min_periods=min_periods) + ): + tm.assert_series_equal(actual, expected) + + +@pytest.mark.parametrize( + "expected,window,min_periods", + [ + ([([0], [0]), ([1], [1]), ([2], [2]), ([3], [3]), ([4], [4])], "1s", None), + ( + [ + ([0], [0]), + ([0, 1], [0, 1]), + ([1, 2], [1, 2]), + ([2, 3], [2, 3]), + ([3, 4], [3, 4]), + ], + "2S", + 1, + ), + ( + [ + ([0], [0]), + ([0, 1], [0, 1]), + ([0, 1, 2], [0, 1, 2]), + ([1, 2, 3], [1, 2, 3]), + ([2, 3, 4], [2, 3, 4]), + ], + "3S", + 4, + ), + ([], "1s", 2), + ( + [ + ([0], [0]), + ([0, 1], [0, 1]), + ([0, 1, 2], [0, 1, 2]), + ([1, 2, 3], [1, 2, 3]), + ([2, 3, 4], [2, 3, 4]), + ], + "3S", + 1, + ), + ], +) +def test_iter_rolling_series_time(expected, window, min_periods): + # GH 11704 + series = Series( + range(5), index=date_range(start="2016-01-01 09:30:00", periods=5, freq="s") + ) + + expected = [ + Series(values, index=series.index[index]) for (values, index) in expected + ] + + for (expected, actual) in zip(expected, series.rolling(window)): + tm.assert_series_equal(actual, expected) From fe74bc9811ddbcd21053ff954b75ad2960de8b8e Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Fri, 15 May 2020 23:32:08 +0200 Subject: [PATCH 06/18] add doc --- 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 73892da2cbf71..eaf8c19b9a21b 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -235,6 +235,7 @@ Other enhancements :class:`~pandas.io.stata.StataWriter`, :class:`~pandas.io.stata.StataWriter117`, and :class:`~pandas.io.stata.StataWriterUTF8` (:issue:`26599`). - :meth:`HDFStore.put` now accepts `track_times` parameter. Parameter is passed to ``create_table`` method of ``PyTables`` (:issue:`32682`). +- Make :class:`pandas.core.window.Rolling` and :class:`pandas.core.window.Expanding` iterable(:issue:`11704`) .. --------------------------------------------------------------------------- From c0f4cf491b1f3bb1f77dfb31f75cb77d92069017 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Fri, 15 May 2020 23:34:45 +0200 Subject: [PATCH 07/18] pep8 --- pandas/tests/window/test_expanding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/window/test_expanding.py b/pandas/tests/window/test_expanding.py index c156cc856eced..0acdf7c5b0684 100644 --- a/pandas/tests/window/test_expanding.py +++ b/pandas/tests/window/test_expanding.py @@ -158,7 +158,7 @@ def test_expanding_count_default_min_periods_with_null_values(constructor): ), ( DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), - [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]),], + [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), ], 2, ), ( From 3bb2cf01b2dbb4cdbac3d782ab3d8edbb6d9097d Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 00:47:51 +0200 Subject: [PATCH 08/18] fixup --- pandas/tests/window/test_rolling.py | 63 ++--------------------------- 1 file changed, 4 insertions(+), 59 deletions(-) diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index 0414309101a22..b955fec28520e 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -7,7 +7,7 @@ import pandas.util._test_decorators as td import pandas as pd -from pandas import DataFrame, Series, date_range +from pandas import DataFrame, Series import pandas._testing as tm from pandas.core.window import Rolling @@ -472,6 +472,7 @@ def test_rolling_count_default_min_periods_with_null_values(constructor): ( DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), [ + ({"A": [1], "B": [4]}, [0]), ({"A": [1, 2], "B": [4, 5]}, [0, 1]), ({"A": [2, 3], "B": [5, 6]}, [1, 2]), ], @@ -516,8 +517,6 @@ def test_iter_rolling_dataframe(df, expected, window, min_periods): for (expected, actual) in zip( expected, df.rolling(window, min_periods=min_periods) ): - print(expected) - print(actual) tm.assert_frame_equal(actual, expected) @@ -525,11 +524,11 @@ def test_iter_rolling_dataframe(df, expected, window, min_periods): "ser,expected,window, min_periods", [ (Series([1, 2, 3]), [([1, 2, 3], [0, 1, 2])], 3, None), - (Series([1, 2, 3]), [([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 1), + (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 1), (Series([1, 2, 3]), [([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 3), (Series([1, 2, 3]), [([1], [0]), ([2], [1]), ([3], [2])], 1, 0), (Series([1, 2, 3]), [([1], [0]), ([2], [1]), ([3], [2])], 1, 2), - (Series([1, 2]), [([1, 2], [0, 1])], 2, 0), + (Series([1, 2]), [([1], [0]), ([1, 2], [0, 1])], 2, 0), (Series([1, 2]), [([1, 2], [0, 1])], 2, 3), (Series([], dtype="int64"), [], 2, 1), (Series([], dtype="int64"), [], 2, 3), @@ -543,57 +542,3 @@ def test_iter_rolling_series(ser, expected, window, min_periods): expected, ser.rolling(window, min_periods=min_periods) ): tm.assert_series_equal(actual, expected) - - -@pytest.mark.parametrize( - "expected,window,min_periods", - [ - ([([0], [0]), ([1], [1]), ([2], [2]), ([3], [3]), ([4], [4])], "1s", None), - ( - [ - ([0], [0]), - ([0, 1], [0, 1]), - ([1, 2], [1, 2]), - ([2, 3], [2, 3]), - ([3, 4], [3, 4]), - ], - "2S", - 1, - ), - ( - [ - ([0], [0]), - ([0, 1], [0, 1]), - ([0, 1, 2], [0, 1, 2]), - ([1, 2, 3], [1, 2, 3]), - ([2, 3, 4], [2, 3, 4]), - ], - "3S", - 4, - ), - ([], "1s", 2), - ( - [ - ([0], [0]), - ([0, 1], [0, 1]), - ([0, 1, 2], [0, 1, 2]), - ([1, 2, 3], [1, 2, 3]), - ([2, 3, 4], [2, 3, 4]), - ], - "3S", - 1, - ), - ], -) -def test_iter_rolling_series_time(expected, window, min_periods): - # GH 11704 - series = Series( - range(5), index=date_range(start="2016-01-01 09:30:00", periods=5, freq="s") - ) - - expected = [ - Series(values, index=series.index[index]) for (values, index) in expected - ] - - for (expected, actual) in zip(expected, series.rolling(window)): - tm.assert_series_equal(actual, expected) From ac23518074dc8dc8013c7c1b2c8c8af1bb34570a Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 00:49:16 +0200 Subject: [PATCH 09/18] linting --- pandas/tests/window/test_expanding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/window/test_expanding.py b/pandas/tests/window/test_expanding.py index 0acdf7c5b0684..428d18ff2a9c4 100644 --- a/pandas/tests/window/test_expanding.py +++ b/pandas/tests/window/test_expanding.py @@ -158,7 +158,7 @@ def test_expanding_count_default_min_periods_with_null_values(constructor): ), ( DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), - [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), ], + [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2])], 2, ), ( From 7f74b794af820b0a92175a50e992ed9e3e242bdc Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 10:24:45 +0200 Subject: [PATCH 10/18] add tests --- pandas/core/window/rolling.py | 30 +++++---- pandas/tests/window/test_rolling.py | 96 ++++++++++++++++++++++++++++- 2 files changed, 109 insertions(+), 17 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 9596a0e21dc33..2932bd07a6e9c 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -250,7 +250,6 @@ def __iter__(self): window = self._get_window(win_type=None) blocks, obj = self._create_blocks() - block_list = list(blocks) index = self._get_window_indexer(window=window) # Choose the min between min_periods and window to determine the output size @@ -259,21 +258,20 @@ def __iter__(self): else: iter_threshold = min(window, self.min_periods) - for block in block_list: - start, end = index.get_window_bounds( - num_values=len(block), - min_periods=self.min_periods, - center=self.center, - closed=self.closed, - ) - # From get_window_bounds, those two should be equal in length of array - assert len(start) == len(end) - - window_size = len(start) - for i in range(window_size): - result = block.iloc[slice(start[i], end[i])] - if result.count().min() >= iter_threshold: - yield result + start, end = index.get_window_bounds( + num_values=len(obj), + min_periods=self.min_periods, + center=self.center, + closed=self.closed, + ) + # From get_window_bounds, those two should be equal in length of array + assert len(start) == len(end) + + window_size = len(start) + for i in range(window_size): + result = obj.iloc[slice(start[i], end[i])] + if result.count().min() >= iter_threshold: + yield result def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: """Convert input to numpy arrays for Cython routines""" diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index b955fec28520e..53b52fbd2fa32 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -7,7 +7,7 @@ import pandas.util._test_decorators as td import pandas as pd -from pandas import DataFrame, Series +from pandas import DataFrame, Series, date_range import pandas._testing as tm from pandas.core.window import Rolling @@ -520,6 +520,50 @@ def test_iter_rolling_dataframe(df, expected, window, min_periods): tm.assert_frame_equal(actual, expected) +@pytest.mark.parametrize( + "expected,window", + [ + ( + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [2, 3], "B": [5, 6]}, [1, 2]), + ], + "2D", + ), + ( + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2]), + ], + "3D", + ), + ( + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [2], "B": [5]}, [1]), + ({"A": [3], "B": [6]}, [2]), + ], + "1D", + ), + ], +) +def test_iter_rolling_on_dataframe(expected, window): + # GH 11704 + df = DataFrame( + { + "A": [1, 2, 3, 4, 5], + "B": [4, 5, 6, 7, 8], + "C": date_range(start="2016-01-01", periods=5, freq="D"), + } + ) + + expected = [DataFrame(values, index=index) for (values, index) in expected] + for (expected, actual) in zip(expected, df.rolling(window, on="C")): + tm.assert_frame_equal(actual, expected) + + @pytest.mark.parametrize( "ser,expected,window, min_periods", [ @@ -542,3 +586,53 @@ def test_iter_rolling_series(ser, expected, window, min_periods): expected, ser.rolling(window, min_periods=min_periods) ): tm.assert_series_equal(actual, expected) + + +@pytest.mark.parametrize( + "expected,expected_index,window", + [ + ( + [[0], [1], [2], [3], [4]], + [ + date_range("2020-01-01", periods=1, freq="D"), + date_range("2020-01-02", periods=1, freq="D"), + date_range("2020-01-03", periods=1, freq="D"), + date_range("2020-01-04", periods=1, freq="D"), + date_range("2020-01-05", periods=1, freq="D"), + ], + "1D", + ), + ( + [[0], [0, 1], [1, 2], [2, 3], [3, 4]], + [ + date_range("2020-01-01", periods=1, freq="D"), + date_range("2020-01-01", periods=2, freq="D"), + date_range("2020-01-02", periods=2, freq="D"), + date_range("2020-01-03", periods=2, freq="D"), + date_range("2020-01-04", periods=2, freq="D"), + ], + "2D", + ), + ( + [[0], [0, 1], [0, 1, 2], [1, 2, 3], [2, 3, 4]], + [ + date_range("2020-01-01", periods=1, freq="D"), + date_range("2020-01-01", periods=2, freq="D"), + date_range("2020-01-01", periods=3, freq="D"), + date_range("2020-01-02", periods=3, freq="D"), + date_range("2020-01-03", periods=3, freq="D"), + ], + "3D", + ), + ], +) +def test_iter_rolling_datetime(expected, expected_index, window): + # GH 11704 + ser = Series(range(5), index=date_range(start="2020-01-01", periods=5, freq="D")) + + expected = [ + Series(values, index=idx) for (values, idx) in zip(expected, expected_index) + ] + + for (expected, actual) in zip(expected, ser.rolling(window)): + tm.assert_series_equal(actual, expected) From 5577efc1218ee172e0cb2a8ed4eeef71873a9620 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 21:41:06 +0200 Subject: [PATCH 11/18] better python --- pandas/core/window/rolling.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index 2932bd07a6e9c..c6f1c2dbfd2ea 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -248,7 +248,6 @@ def __repr__(self) -> str: def __iter__(self): window = self._get_window(win_type=None) - blocks, obj = self._create_blocks() index = self._get_window_indexer(window=window) @@ -267,9 +266,8 @@ def __iter__(self): # From get_window_bounds, those two should be equal in length of array assert len(start) == len(end) - window_size = len(start) - for i in range(window_size): - result = obj.iloc[slice(start[i], end[i])] + for s, e in zip(start, end): + result = obj.iloc[slice(s, e)] if result.count().min() >= iter_threshold: yield result From fd6e9a9e3bb813fc238b18dfd216532fd395269b Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 21:51:15 +0200 Subject: [PATCH 12/18] raise error --- pandas/core/window/rolling.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index c6f1c2dbfd2ea..a566ef55a88d2 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -251,11 +251,11 @@ def __iter__(self): blocks, obj = self._create_blocks() index = self._get_window_indexer(window=window) - # Choose the min between min_periods and window to determine the output size - if self.min_periods is None: - iter_threshold = window - else: - iter_threshold = min(window, self.min_periods) + # min_periods cannot be larger than window + if self.min_periods is not None and self.min_periods > window: + raise ValueError( + f"min_periods {self.min_periods} must be <= window {window}" + ) start, end = index.get_window_bounds( num_values=len(obj), @@ -268,8 +268,7 @@ def __iter__(self): for s, e in zip(start, end): result = obj.iloc[slice(s, e)] - if result.count().min() >= iter_threshold: - yield result + yield result def _prep_values(self, values: Optional[np.ndarray] = None) -> np.ndarray: """Convert input to numpy arrays for Cython routines""" From 3cefb2324b2fa7005f89b9b5e197a9a438dd0d61 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 22:02:03 +0200 Subject: [PATCH 13/18] fix expanding --- pandas/tests/window/test_expanding.py | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/pandas/tests/window/test_expanding.py b/pandas/tests/window/test_expanding.py index 428d18ff2a9c4..b57467385d371 100644 --- a/pandas/tests/window/test_expanding.py +++ b/pandas/tests/window/test_expanding.py @@ -129,12 +129,17 @@ def test_expanding_count_default_min_periods_with_null_values(constructor): [ ( DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), - [({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2])], + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2]), + ], 3, ), ( DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), [ + ({"A": [1], "B": [4]}, [0]), ({"A": [1, 2], "B": [4, 5]}, [0, 1]), ({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2]), ], @@ -153,17 +158,26 @@ def test_expanding_count_default_min_periods_with_null_values(constructor): (DataFrame(), [({}, [])], 1), ( DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), - [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2])], + [ + ({"A": [1.0], "B": [np.nan]}, [0]), + ({"A": [1, np.nan], "B": [np.nan, 5]}, [0, 1]), + ({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), + ], 3, ), ( DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), - [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2])], + [ + ({"A": [1.0], "B": [np.nan]}, [0]), + ({"A": [1, np.nan], "B": [np.nan, 5]}, [0, 1]), + ({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), + ], 2, ), ( DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), [ + ({"A": [1.0], "B": [np.nan]}, [0]), ({"A": [1, np.nan], "B": [np.nan, 5]}, [0, 1]), ({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), ], @@ -182,11 +196,11 @@ def test_iter_expanding_dataframe(df, expected, min_periods): @pytest.mark.parametrize( "ser,expected,min_periods", [ - (Series([1, 2, 3]), [([1, 2, 3], [0, 1, 2])], 3), - (Series([1, 2, 3]), [([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], 2), + (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], 3), + (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], 2), (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], 1), - (Series([1, 2]), [([1, 2], [0, 1])], 2), - (Series([np.nan, 2]), [([np.nan, 2], [0, np.nan])], 2), + (Series([1, 2]), [([1], [0]), ([1, 2], [0, 1])], 2), + (Series([np.nan, 2]), [([np.nan], [0]), ([np.nan, 2], [0, 1])], 2), (Series([], dtype="int64"), [], 2), ], ) From 16235935d967ced80a0738fe01427255123ab6ca Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 22:11:40 +0200 Subject: [PATCH 14/18] updates --- pandas/core/window/rolling.py | 6 ----- pandas/tests/window/test_rolling.py | 41 ++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index a566ef55a88d2..c615e18af68e6 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -251,12 +251,6 @@ def __iter__(self): blocks, obj = self._create_blocks() index = self._get_window_indexer(window=window) - # min_periods cannot be larger than window - if self.min_periods is not None and self.min_periods > window: - raise ValueError( - f"min_periods {self.min_periods} must be <= window {window}" - ) - start, end = index.get_window_bounds( num_values=len(obj), min_periods=self.min_periods, diff --git a/pandas/tests/window/test_rolling.py b/pandas/tests/window/test_rolling.py index 53b52fbd2fa32..f9b0e6856337b 100644 --- a/pandas/tests/window/test_rolling.py +++ b/pandas/tests/window/test_rolling.py @@ -465,7 +465,11 @@ def test_rolling_count_default_min_periods_with_null_values(constructor): [ ( DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), - [({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2])], + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [1, 2], "B": [4, 5]}, [0, 1]), + ({"A": [1, 2, 3], "B": [4, 5, 6]}, [0, 1, 2]), + ], 3, None, ), @@ -482,6 +486,7 @@ def test_rolling_count_default_min_periods_with_null_values(constructor): ( DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), [ + ({"A": [1], "B": [4]}, [0]), ({"A": [1, 2], "B": [4, 5]}, [0, 1]), ({"A": [2, 3], "B": [5, 6]}, [1, 2]), ], @@ -498,13 +503,26 @@ def test_rolling_count_default_min_periods_with_null_values(constructor): 1, 1, ), + ( + DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}), + [ + ({"A": [1], "B": [4]}, [0]), + ({"A": [2], "B": [5]}, [1]), + ({"A": [3], "B": [6]}, [2]), + ], + 1, + 2, + ), (DataFrame({"A": [1], "B": [4]}), [], 2, None), (DataFrame({"A": [1], "B": [4]}), [], 2, 1), (DataFrame(), [({}, [])], 2, None), - (DataFrame(), [({}, [])], 1, 2), ( DataFrame({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}), - [({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2])], + [ + ({"A": [1.0], "B": [np.nan]}, [0]), + ({"A": [1, np.nan], "B": [np.nan, 5]}, [0, 1]), + ({"A": [1, np.nan, 3], "B": [np.nan, 5, 6]}, [0, 1, 2]), + ], 3, 2, ), @@ -567,15 +585,24 @@ def test_iter_rolling_on_dataframe(expected, window): @pytest.mark.parametrize( "ser,expected,window, min_periods", [ - (Series([1, 2, 3]), [([1, 2, 3], [0, 1, 2])], 3, None), + ( + Series([1, 2, 3]), + [([1], [0]), ([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], + 3, + None, + ), + ( + Series([1, 2, 3]), + [([1], [0]), ([1, 2], [0, 1]), ([1, 2, 3], [0, 1, 2])], + 3, + 1, + ), (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 1), - (Series([1, 2, 3]), [([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 3), + (Series([1, 2, 3]), [([1], [0]), ([1, 2], [0, 1]), ([2, 3], [1, 2])], 2, 3), (Series([1, 2, 3]), [([1], [0]), ([2], [1]), ([3], [2])], 1, 0), (Series([1, 2, 3]), [([1], [0]), ([2], [1]), ([3], [2])], 1, 2), (Series([1, 2]), [([1], [0]), ([1, 2], [0, 1])], 2, 0), - (Series([1, 2]), [([1, 2], [0, 1])], 2, 3), (Series([], dtype="int64"), [], 2, 1), - (Series([], dtype="int64"), [], 2, 3), ], ) def test_iter_rolling_series(ser, expected, window, min_periods): From 61af13576603ee5b26191b2d7defc91ee3f570f5 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sat, 16 May 2020 23:07:42 +0200 Subject: [PATCH 15/18] add user guide --- doc/source/user_guide/computation.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index d371f6d5f273c..607692935826a 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -648,6 +648,30 @@ from present information back to past information. This allows the rolling windo Currently, this feature is only implemented for time-based windows. For fixed windows, the closed parameter cannot be set and the rolling window will always have both endpoints closed. +.. _stats.rolling_window.iter: + +Iteration over window: +~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.1.0 + +It is allowed to iterate over the Series and DataFrame with the ``rolling`` and ``expanding`` window are +support. + +Be noted that for ``rolling``, even if ``min_periods`` is greater than ``window`` size , we can still iterate +all the result out, although it will raise an error during aggregation. + +.. ipython:: python + ser = pd.Series([1, 2, 3]).rolling(2) + for i in ser: + i + +.. ipython:: python + df = pd.DataFrame({ "A": [1, 2, 3], "B": [4, 5, 6]}).rolling(2) + for i in df: + i + + .. _stats.moments.ts-versus-resampling: Time-aware rolling vs. resampling From 7e85f8737d12f083624c5729c31d1e50135da4b2 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 09:24:59 +0200 Subject: [PATCH 16/18] rephrase doc --- doc/source/user_guide/computation.rst | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 607692935826a..3fd62f01c8286 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -655,21 +655,12 @@ Iteration over window: .. versionadded:: 1.1.0 -It is allowed to iterate over the Series and DataFrame with the ``rolling`` and ``expanding`` window are -support. - -Be noted that for ``rolling``, even if ``min_periods`` is greater than ``window`` size , we can still iterate -all the result out, although it will raise an error during aggregation. - -.. ipython:: python - ser = pd.Series([1, 2, 3]).rolling(2) - for i in ser: - i +``Rolling`` and ``Expanding`` objects now support iteration. Be noted that ``min_periods`` is ignored in iteration. .. ipython:: python - df = pd.DataFrame({ "A": [1, 2, 3], "B": [4, 5, 6]}).rolling(2) - for i in df: - i + df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) + for i in df.rolling(2): + print(i) .. _stats.moments.ts-versus-resampling: From 9b84e74782c436e978d6977c6a916e8e3bfe0920 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 10:37:20 +0200 Subject: [PATCH 17/18] fix web doc error --- doc/source/user_guide/computation.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 3fd62f01c8286..47148d961ea0d 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -648,7 +648,7 @@ from present information back to past information. This allows the rolling windo Currently, this feature is only implemented for time-based windows. For fixed windows, the closed parameter cannot be set and the rolling window will always have both endpoints closed. -.. _stats.rolling_window.iter: +.. _stats.iter_rolling_window: Iteration over window: ~~~~~~~~~~~~~~~~~~~~~~ @@ -658,7 +658,9 @@ Iteration over window: ``Rolling`` and ``Expanding`` objects now support iteration. Be noted that ``min_periods`` is ignored in iteration. .. ipython:: python + df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) + for i in df.rolling(2): print(i) From 8379810ffd858590330c0e591ef0db75f1c1eea4 Mon Sep 17 00:00:00 2001 From: Kaiqi Date: Sun, 17 May 2020 10:43:44 +0200 Subject: [PATCH 18/18] fixup doc --- doc/source/user_guide/computation.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index 47148d961ea0d..cf630a9671013 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -657,12 +657,13 @@ Iteration over window: ``Rolling`` and ``Expanding`` objects now support iteration. Be noted that ``min_periods`` is ignored in iteration. -.. ipython:: python +.. ipython:: - df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) + In [1]: df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) - for i in df.rolling(2): - print(i) + In [2]: for i in df.rolling(2): + ...: print(i) + ...: .. _stats.moments.ts-versus-resampling: