Skip to content

Commit 915d261

Browse files
committed
ENH: centered moving windows for array input
1 parent bda1452 commit 915d261

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

RELEASE.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ pandas 0.10.0
3636
for both Series and DataFrame (#2002)
3737
- Add ``duplicated`` and ``drop_duplicates`` functions to Series (#1923)
3838
- Add docs for ``HDFStore table`` format
39-
- 'density' property in `SparseSeries` (#2384)
39+
- 'density' property in ``SparseSeries`` (#2384)
40+
- Centered moving window functions via ``center`` keyword (#1270)
4041

4142
**API Changes**
4243

pandas/stats/moments.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,26 @@ def _rolling_moment(arg, window, func, minp, axis=0, freq=None,
281281

282282
rs = return_hook(result)
283283
if center:
284-
if isinstance(rs, (Series, DataFrame, Panel)):
285-
rs = rs.shift(-int((window + 1) / 2.), axis=axis)
286-
else:
287-
offset = int((window + 1)/ 2.)
288-
rs[:-offset] = rs[offset:]
289-
rs[-offset:] = np.nan
284+
rs = _center_window(rs, window, axis)
285+
return rs
286+
287+
def _center_window(rs, window, axis):
288+
if isinstance(rs, (Series, DataFrame, Panel)):
289+
rs = rs.shift(-int((window + 1) / 2.), axis=axis)
290+
else:
291+
offset = int((window + 1) / 2.)
292+
293+
rs_indexer = [slice(None)] * rs.ndim
294+
rs_indexer[axis] = slice(None, -offset)
295+
296+
lead_indexer = [slice(None)] * rs.ndim
297+
lead_indexer[axis] = slice(offset, None)
298+
299+
na_indexer = [slice(None)] * rs.ndim
300+
na_indexer[axis] = slice(-offset, None)
290301

302+
rs[rs_indexer] = rs[lead_indexer]
303+
rs[na_indexer] = np.nan
291304
return rs
292305

293306
def _process_data_structure(arg, kill_inf=True):

pandas/stats/tests/test_moments.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -190,22 +190,28 @@ def test_fperr_robustness(self):
190190

191191
def _check_moment_func(self, func, static_comp, window=50,
192192
has_min_periods=True,
193+
has_center=True,
193194
has_time_rule=True,
194195
preserve_nan=True,
195196
fill_value=None):
196197

197198
self._check_ndarray(func, static_comp, window=window,
198199
has_min_periods=has_min_periods,
199-
preserve_nan=preserve_nan)
200+
preserve_nan=preserve_nan,
201+
has_center=has_center,
202+
fill_value=fill_value)
200203

201204
self._check_structures(func, static_comp,
202205
has_min_periods=has_min_periods,
203206
has_time_rule=has_time_rule,
204-
fill_value=fill_value)
207+
fill_value=fill_value,
208+
has_center=has_center)
205209

206210
def _check_ndarray(self, func, static_comp, window=50,
207211
has_min_periods=True,
208-
preserve_nan=True):
212+
preserve_nan=True,
213+
has_center=True,
214+
fill_value=None):
209215

210216
result = func(self.arr, window)
211217
assert_almost_equal(result[-1],
@@ -244,6 +250,26 @@ def _check_ndarray(self, func, static_comp, window=50,
244250
result = func(arr, 50)
245251
assert_almost_equal(result[-1], static_comp(arr[10:-10]))
246252

253+
254+
if has_center:
255+
if has_min_periods:
256+
result = func(arr, 20, min_periods=15, center=True)
257+
expected = func(arr, 20, min_periods=15)
258+
else:
259+
result = func(arr, 20, center=True)
260+
expected = func(arr, 20)
261+
262+
assert_almost_equal(result[0], expected[10])
263+
if fill_value is None:
264+
self.assert_(np.isnan(result[-10:]).all())
265+
else:
266+
self.assert_((result[-10:] == 0).all())
267+
if has_min_periods:
268+
self.assert_(np.isnan(expected[23]))
269+
self.assert_(np.isnan(result[13]))
270+
self.assert_(np.isnan(expected[-5]))
271+
self.assert_(np.isnan(result[-15]))
272+
247273
def _check_structures(self, func, static_comp,
248274
has_min_periods=True, has_time_rule=True,
249275
has_center=True,

0 commit comments

Comments
 (0)