Skip to content

Commit

Permalink
BUG: fixed up cmoment functions
Browse files Browse the repository at this point in the history
BUG: fixed rolling_kurt/skew
  • Loading branch information
jreback committed Mar 18, 2013
1 parent 71d7435 commit db78efb
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 42 deletions.
17 changes: 11 additions & 6 deletions pandas/algos.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1104,8 +1104,11 @@ def roll_skew(ndarray[double_t] input, int win, int minp):

R = sqrt(B)

output[i] = ((sqrt(nobs * (nobs - 1.)) * C) /
((nobs-2) * R * R * R))
if R != 0 and nobs > 2:
output[i] = ((sqrt(nobs * (nobs - 1.)) * C) /
((nobs-2) * R * R * R))
else:
output[i] = NaN
else:
output[i] = NaN

Expand Down Expand Up @@ -1173,10 +1176,12 @@ def roll_kurt(ndarray[double_t] input,
R = R * A
D = xxxx / nobs - R - 6*B*A*A - 4*C*A

K = (nobs * nobs - 1.)*D/(B*B) - 3*((nobs-1.)**2)
K = K / ((nobs - 2.)*(nobs-3.))

output[i] = K
if B != 0 and nobs > 3:
K = (nobs * nobs - 1.)*D/(B*B) - 3*((nobs-1.)**2)
K = K / ((nobs - 2.)*(nobs-3.))
output[i] = K
else:
output[i] = NaN
else:
output[i] = NaN

Expand Down
101 changes: 65 additions & 36 deletions pandas/stats/moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,12 +148,17 @@ def rolling_count(arg, window, freq=None, center=False, time_rule=None):
return_hook, values = _process_data_structure(arg, kill_inf=False)

converted = np.isfinite(values).astype(float)
result = rolling_sum(converted, window, min_periods=1,
center=center) # already converted
if center:
center = ('na','na')
converted = _center_window(converted, window, 0, center=center)
result = rolling_sum(converted, window, min_periods=1,
center=False)
else:

# putmask here?
result[np.isnan(result)] = 0
result = rolling_sum(converted, window, min_periods=1,
center=center)

result[np.isnan(result)] = 0
return return_hook(result)


Expand Down Expand Up @@ -277,50 +282,58 @@ def _rolling_moment(arg, window, func, minp, axis=0, freq=None,
y : type of input
"""
arg = _conv_timerule(arg, freq, time_rule)
calc = lambda x: func(x, window, minp=minp, **kwargs)
return_hook, values = _process_data_structure(arg)

# actually calculate the moment. Faster way to do this?
if values.ndim > 1:
result = np.apply_along_axis(calc, axis, values)
else:
result = calc(values)
def calc(x):
_calc = lambda x: func(x, window, minp=minp, **kwargs)
if x.ndim > 1:
return np.apply_along_axis(_calc, axis, x)
else:
return _calc(x)

result = calc(values)
rs = return_hook(result)
if center:
rs = _center_window(rs, window, axis)
rs = _center_window(rs, window, axis, center=center)
# GH2953, fixup edges
if window > 2:
if values.ndim > 1:
# TODO: handle mi vectorized case
pass

# there's an ambiguity on what constitutes
# the "center" when window is even
# we Just close ranks with numpy , see test case
# delta = 1 if window % 2 == 0 else 0
if window % 2 == 0 :
nahead = (window-1)//2 or 1
else:
# there's an ambiguity on what constitutes
# the "center" when window is even
# we Just close ranks with numpy , see test case
# delta = 1 if window % 2 == 0 else 0
if window % 2 == 0 :
nahead = (window-1)//2 or 1
else:
nahead = (window)//2

# fixup the head
tip = np.append(np.zeros(nahead+1),values[:(2*nahead+1)])
rs[:nahead+1] = calc(tip)[-(nahead+1):][:nahead+1]

# fixup the tail
tip = np.append(values[-(2*nahead+1):],np.zeros(nahead))
rs[-(nahead):] = calc(tip)[-(nahead):]

if minp > 0:
d = minp - nahead-1
if d > 0:
rs[:d] = NaN
rs[-(d):] = NaN
nahead = (window)//2

# fixup the head
shape = list(values.shape)
shape[0] = nahead+1
tip = np.append(np.zeros(tuple(shape)),values[:(2*nahead+1)],axis=0)
rs[:nahead+1] = calc(tip)[-(nahead+1):][:nahead+1]
if minp > 0:
d = max(minp,nahead+1)
if d > 0:
rs[:d] = NaN


# fixup the tail
shape = list(values.shape)
shape[0] = nahead
tip = np.append(values[-(2*nahead+1):],np.zeros(tuple(shape)),axis=0)
rs[-(nahead):] = calc(tip)[-(nahead):]

if minp > 0:
d = max(nahead,minp)
if d > 0:
rs[-d:] = NaN

return rs


def _center_window(rs, window, axis):
def _center_window(rs, window, axis, center=None):
offset = int((window - 1) / 2.)
if isinstance(rs, (Series, DataFrame, Panel)):
rs = rs.shift(-offset, axis=axis)
Expand All @@ -335,7 +348,23 @@ def _center_window(rs, window, axis):
na_indexer[axis] = slice(-offset, None)

rs[tuple(rs_indexer)] = np.copy(rs[tuple(lead_indexer)])

# center can optionally point to an action on
# lhs or rhs

if not isinstance(center, tuple):
center = ('copy','na')
lhs, rhs = center

# lhs : default is copy
if lhs == 'na':
lhs_indexer = [slice(None)] * rs.ndim
lhs_indexer[axis] = slice(0, offset+1)
rs[tuple(lhs_indexer)] = np.nan

# rhs : default is na
rs[tuple(na_indexer)] = np.nan

return rs


Expand Down
2 changes: 2 additions & 0 deletions pandas/stats/tests/test_moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,9 @@ def _check_structures(self, func, static_comp,
if has_min_periods:
minp = 10
series_xp = func(self.series, 25, min_periods=minp).shift(-12)
series_xp[:13] = np.nan
frame_xp = func(self.frame, 25, min_periods=minp).shift(-12)
frame_xp[:13] = np.nan

series_rs = func(self.series, 25, min_periods=minp,
center=True)
Expand Down

0 comments on commit db78efb

Please sign in to comment.