Skip to content

Commit

Permalink
ENH: add adjust option to ewma to disable adjustment close #1584
Browse files Browse the repository at this point in the history
  • Loading branch information
wesm committed Jul 13, 2012
1 parent 4bebdfe commit 9a0e52a
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 20 deletions.
1 change: 1 addition & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pandas 0.8.1
to PeriodIndex inside Index (#1215)
- More informative string representation for weekly Period objects (#1503)
- Accelerate 3-axis multi data selection from homogeneous Panel (#979)
- Add ``adjust`` option to ewma to disable adjustment factor (#1584)

**Bug fixes**

Expand Down
13 changes: 7 additions & 6 deletions pandas/src/moments.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def roll_mean(ndarray[double_t] input,
#-------------------------------------------------------------------------------
# Exponentially weighted moving average

def ewma(ndarray[double_t] input, double_t com):
def ewma(ndarray[double_t] input, double_t com, int adjust):
'''
Compute exponentially-weighted moving average using center-of-mass.
Expand Down Expand Up @@ -266,12 +266,13 @@ def ewma(ndarray[double_t] input, double_t com):
else:
output[i] = prev

for i from 0 <= i < N:
cur = input[i]
output[i] = output[i] / (1. - adj)
if adjust:
for i from 0 <= i < N:
cur = input[i]
output[i] = output[i] / (1. - adj)

if cur == cur:
adj *= oldw
if cur == cur:
adj *= oldw

return output

Expand Down
33 changes: 19 additions & 14 deletions pandas/stats/moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import numpy as np

from pandas.core.api import DataFrame, Series, notnull
import pandas.lib as _tseries
import pandas.lib as lib

from pandas.util.decorators import Substitution, Appender

Expand Down Expand Up @@ -56,6 +56,10 @@
beginning)
freq : None or string alias / date offset object, default=None
Frequency to conform to before computing statistic
adjust : boolean, default True
Divide by decaying adjustment factor in beginning periods to account for
imbalance in relative weightings (viewing EWMA as a moving average)
%s
Notes
-----
Expand Down Expand Up @@ -265,12 +269,13 @@ def _get_center_of_mass(com, span):

@Substitution("Exponentially-weighted moving average", _unary_arg, "")
@Appender(_ewm_doc)
def ewma(arg, com=None, span=None, min_periods=0, freq=None, time_rule=None):
def ewma(arg, com=None, span=None, min_periods=0, freq=None, time_rule=None,
adjust=True):
com = _get_center_of_mass(com, span)
arg = _conv_timerule(arg, freq, time_rule)

def _ewma(v):
result = _tseries.ewma(v, com)
result = lib.ewma(v, com, int(adjust))
first_index = _first_valid_index(v)
result[first_index : first_index + min_periods] = NaN
return result
Expand Down Expand Up @@ -395,20 +400,20 @@ def call_cython(arg, window, minp, **kwds):

return f

rolling_max = _rolling_func(_tseries.roll_max2, 'Moving maximum')
rolling_min = _rolling_func(_tseries.roll_min2, 'Moving minimum')
rolling_sum = _rolling_func(_tseries.roll_sum, 'Moving sum')
rolling_mean = _rolling_func(_tseries.roll_mean, 'Moving mean')
rolling_median = _rolling_func(_tseries.roll_median_cython, 'Moving median')
rolling_max = _rolling_func(lib.roll_max2, 'Moving maximum')
rolling_min = _rolling_func(lib.roll_min2, 'Moving minimum')
rolling_sum = _rolling_func(lib.roll_sum, 'Moving sum')
rolling_mean = _rolling_func(lib.roll_mean, 'Moving mean')
rolling_median = _rolling_func(lib.roll_median_cython, 'Moving median')

_ts_std = lambda *a, **kw: np.sqrt(_tseries.roll_var(*a, **kw))
_ts_std = lambda *a, **kw: np.sqrt(lib.roll_var(*a, **kw))
rolling_std = _rolling_func(_ts_std, 'Unbiased moving standard deviation',
check_minp=_require_min_periods(2))
rolling_var = _rolling_func(_tseries.roll_var, 'Unbiased moving variance',
rolling_var = _rolling_func(lib.roll_var, 'Unbiased moving variance',
check_minp=_require_min_periods(2))
rolling_skew = _rolling_func(_tseries.roll_skew, 'Unbiased moving skewness',
rolling_skew = _rolling_func(lib.roll_skew, 'Unbiased moving skewness',
check_minp=_require_min_periods(3))
rolling_kurt = _rolling_func(_tseries.roll_kurt, 'Unbiased moving kurtosis',
rolling_kurt = _rolling_func(lib.roll_kurt, 'Unbiased moving kurtosis',
check_minp=_require_min_periods(4))

def rolling_quantile(arg, window, quantile, min_periods=None, freq=None,
Expand All @@ -432,7 +437,7 @@ def rolling_quantile(arg, window, quantile, min_periods=None, freq=None,

def call_cython(arg, window, minp):
minp = _use_window(minp, window)
return _tseries.roll_quantile(arg, window, minp, quantile)
return lib.roll_quantile(arg, window, minp, quantile)
return _rolling_moment(arg, window, call_cython, min_periods,
freq=freq, time_rule=time_rule)

Expand All @@ -457,6 +462,6 @@ def rolling_apply(arg, window, func, min_periods=None, freq=None,
"""
def call_cython(arg, window, minp):
minp = _use_window(minp, window)
return _tseries.roll_generic(arg, window, minp, func)
return lib.roll_generic(arg, window, minp, func)
return _rolling_moment(arg, window, call_cython, min_periods,
freq=freq, time_rule=time_rule)
5 changes: 5 additions & 0 deletions pandas/stats/tests/test_moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ def test_legacy_time_rule_arg(self):
def test_ewma(self):
self._check_ew(mom.ewma)

arr = np.zeros(1000)
arr[5] = 1
result = mom.ewma(arr, span=100, adjust=False).sum()
self.assert_(np.abs(result - 1) < 1e-2)

def test_ewmvar(self):
self._check_ew(mom.ewmvar)

Expand Down

0 comments on commit 9a0e52a

Please sign in to comment.