Skip to content

Commit

Permalink
BUG: fix sqrt(negative number) issue in rolling_std close #1840
Browse files Browse the repository at this point in the history
  • Loading branch information
wesm committed Sep 7, 2012
1 parent 859aa2c commit 821da97
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 3 deletions.
2 changes: 2 additions & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ pandas 0.8.2
right time zone (#1777)
- Fix DST issues with generating anchored date ranges (#1778)
- Fix issue calling sort on result of Series.unique (#1807)
- Fix numerical issue leading to square root of negative number in
rolling_std (#1840)

pandas 0.8.1
============
Expand Down
20 changes: 17 additions & 3 deletions pandas/stats/moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ def ewmstd(arg, com=None, span=None, min_periods=0, bias=False,
time_rule=None):
result = ewmvar(arg, com=com, span=span, time_rule=time_rule,
min_periods=min_periods, bias=bias)
return np.sqrt(result)
return _zsqrt(result)

ewmvol = ewmstd

Expand Down Expand Up @@ -343,7 +343,21 @@ def ewmcorr(arg1, arg2, com=None, span=None, min_periods=0,
mean = lambda x: ewma(x, com=com, span=span, min_periods=min_periods)
var = lambda x: ewmvar(x, com=com, span=span, min_periods=min_periods,
bias=True)
return (mean(X*Y) - mean(X)*mean(Y)) / np.sqrt(var(X) * var(Y))
return (mean(X*Y) - mean(X)*mean(Y)) / _zsqrt(var(X) * var(Y))


def _zsqrt(x):
result = np.sqrt(x)
mask = x < 0

if isinstance(x, DataFrame):
if mask.values.any():
result[mask] = 0
else:
if mask.any():
result[mask] = 0

return result

def _prep_binary(arg1, arg2):
if not isinstance(arg2, type(arg1)):
Expand Down Expand Up @@ -406,7 +420,7 @@ def call_cython(arg, window, minp, **kwds):
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(lib.roll_var(*a, **kw))
_ts_std = lambda *a, **kw: _zsqrt(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(lib.roll_var, 'Unbiased moving variance',
Expand Down
16 changes: 16 additions & 0 deletions pandas/stats/tests/test_moments.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ def test_rolling_std(self):
self._check_moment_func(functools.partial(mom.rolling_std, ddof=0),
lambda x: np.std(x, ddof=0))

def test_rolling_std_neg_sqrt(self):
# unit test from Bottleneck

# Test move_nanstd for neg sqrt.

a = np.array([0.0011448196318903589,
0.00028718669878572767,
0.00028718669878572767,
0.00028718669878572767,
0.00028718669878572767])
b = mom.rolling_std(a, window=3)
self.assert_(np.isfinite(b[2:]).all())

b = mom.ewmstd(a, span=3)
self.assert_(np.isfinite(b[2:]).all())

def test_rolling_var(self):
self._check_moment_func(mom.rolling_var,
lambda x: np.var(x, ddof=1))
Expand Down

0 comments on commit 821da97

Please sign in to comment.