Skip to content

Commit 8bd336a

Browse files
carlosdanielcsantosjreback
carlosdanielcsantos
authored andcommitted
Almost there
Not allowing closed parameter for fixed windows Passing tests again Updating docs
1 parent 306b9f7 commit 8bd336a

File tree

5 files changed

+44
-19
lines changed

5 files changed

+44
-19
lines changed

doc/source/computation.rst

+24-8
Original file line numberDiff line numberDiff line change
@@ -466,19 +466,35 @@ Rolling window endpoint inclusion
466466

467467
.. versionadded:: 0.20.0
468468

469-
New in version 0.19.0 are the ability to pass an offset (or convertible) to a ``.rolling()`` method and have it produce
470-
variable sized windows based on the passed time window. For each time point, this includes all preceding values occurring
471-
within the indicated time delta.
469+
The inclusion of the interval endpoints in rolling window calculations can be specified with the ``closed``
470+
parameter:
472471

473-
This can be particularly useful for a non-regular time frequency index.
472+
- ``right`` : close right endpoint (default for time-based windows)
473+
- ``left`` : close left endpoint
474+
- ``both`` : close both endpoints (default for fixed windows)
475+
- ``neither`` : open endpoints
476+
477+
For example, having the right endpoint open is useful in many problems that require that there is no contamination
478+
from present information back to past information. This allows the rolling window to compute statistics
479+
"up to that point in time", but not including that point in time.
474480

475481
.. ipython:: python
476482
477-
dft = pd.DataFrame({'B': [0, 1, 2, np.nan, 4]},
478-
index=pd.date_range('20130101 09:00:00', periods=5, freq='s'))
479-
dft
483+
df = pd.DataFrame({'x': [1]*5},
484+
index = [pd.Timestamp('20130101 09:00:01'),
485+
pd.Timestamp('20130101 09:00:02'),
486+
pd.Timestamp('20130101 09:00:03'),
487+
pd.Timestamp('20130101 09:00:04'),
488+
pd.Timestamp('20130101 09:00:06')])
480489
481-
This is a regular frequency index. Using an integer window parameter works to roll along the window frequency.
490+
df["right"] = df.rolling('2s', closed='right').x.sum() # default
491+
df["both"] = df.rolling('2s', closed='both').x.sum()
492+
df["left"] = df.rolling('2s', closed='left').x.sum()
493+
df["open"] = df.rolling('2s', closed='neither').x.sum()
494+
495+
df
496+
497+
Currently, this feature is only implemented for time-based windows.
482498

483499
.. _stats.moments.ts-versus-resampling:
484500

pandas/core/generic.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5962,7 +5962,7 @@ def _add_series_or_dataframe_operations(cls):
59625962

59635963
@Appender(rwindow.rolling.__doc__)
59645964
def rolling(self, window, min_periods=None, freq=None, center=False,
5965-
win_type=None, on=None, axis=0, closed='right'):
5965+
win_type=None, on=None, axis=0, closed=None):
59665966
axis = self._get_axis_number(axis)
59675967
return rwindow.rolling(self, window=window,
59685968
min_periods=min_periods, freq=freq,

pandas/core/window.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ def validate(self):
103103
if self.min_periods is not None and not \
104104
is_integer(self.min_periods):
105105
raise ValueError("min_periods must be an integer")
106-
if self.closed not in ['right', 'both', 'left', 'neither']:
106+
if self.closed is not None and self.closed not in \
107+
['right', 'both', 'left', 'neither']:
107108
raise ValueError("closed must be 'right', 'left', 'both' or "
108109
"'neither'")
109110

@@ -1056,6 +1057,9 @@ def validate(self):
10561057
raise ValueError("window must be an integer")
10571058
elif self.window < 0:
10581059
raise ValueError("window must be non-negative")
1060+
elif self.closed is not None:
1061+
raise ValueError("closed only implemented for datetimelike "
1062+
"and offset based windows")
10591063

10601064
def _validate_monotonic(self):
10611065
""" validate on is monotonic """

pandas/core/window.pyx

+10-9
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ cdef class VariableWindowIndexer(WindowIndexer):
248248
249249
"""
250250
def __init__(self, ndarray input, int64_t win, int64_t minp,
251-
ndarray index, bint left_closed, bint right_closed):
251+
bint left_closed, bint right_closed, ndarray index):
252252

253253
self.is_variable = 1
254254
self.N = len(index)
@@ -330,9 +330,10 @@ def get_window_indexer(input, win, minp, index, closed,
330330
minp: integer, minimum periods
331331
index: 1d ndarray, optional
332332
index to the input array
333-
closed: string, default 'right'
333+
closed: string, default None
334334
{'right', 'left', 'both', 'neither'}
335-
window endpoint closedness
335+
window endpoint closedness. Defaults to 'right' in
336+
VariableWindowIndexer and to 'both' in FixedWindowIndexer
336337
floor: optional
337338
unit for flooring the unit
338339
use_mock: boolean, default True
@@ -365,14 +366,14 @@ def get_window_indexer(input, win, minp, index, closed,
365366
left_closed = True
366367

367368
if index is not None:
368-
indexer = VariableWindowIndexer(input, win, minp, index, left_closed,
369-
right_closed)
369+
indexer = VariableWindowIndexer(input, win, minp, left_closed,
370+
right_closed, index)
370371
elif use_mock:
371-
indexer = MockFixedWindowIndexer(input, win, minp, index, floor,
372-
left_closed, right_closed)
372+
indexer = MockFixedWindowIndexer(input, win, minp, left_closed,
373+
right_closed, index, floor)
373374
else:
374-
indexer = FixedWindowIndexer(input, win, minp, index, floor, left_closed,
375-
right_closed)
375+
indexer = FixedWindowIndexer(input, win, minp, left_closed,
376+
right_closed, index, floor)
376377
return indexer.get_data()
377378

378379
# ----------------------------------------------------------------------

pandas/tests/test_window.py

+4
Original file line numberDiff line numberDiff line change
@@ -3396,6 +3396,10 @@ def test_closed(self):
33963396
pd.Timestamp('20130101 09:00:04'),
33973397
pd.Timestamp('20130101 09:00:06')])
33983398

3399+
# closed only allowed for datetimelike
3400+
with self.assertRaises(ValueError):
3401+
self.regular.rolling(window=3, closed='both')
3402+
33993403
# closed must be 'right', 'left', 'both', 'neither'
34003404
with self.assertRaises(ValueError):
34013405
self.regular.rolling(window='2s', closed="blabla")

0 commit comments

Comments
 (0)