diff --git a/doc/source/user_guide/computation.rst b/doc/source/user_guide/computation.rst index c96e066a5874b..466486586f50b 100644 --- a/doc/source/user_guide/computation.rst +++ b/doc/source/user_guide/computation.rst @@ -365,7 +365,8 @@ The list of recognized types are the `scipy.signal window functions * ``kaiser`` (needs beta) * ``gaussian`` (needs std) * ``general_gaussian`` (needs power, width) -* ``slepian`` (needs width). +* ``slepian`` (needs width) +* ``exponential`` (needs tau). .. ipython:: python diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 3e1ce702f0423..578e24009d35a 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -39,6 +39,7 @@ Other Enhancements - :class:`datetime.timezone` objects are now supported as arguments to timezone methods and constructors (:issue:`25065`) - :meth:`DataFrame.query` and :meth:`DataFrame.eval` now supports quoting column names with backticks to refer to names with spaces (:issue:`6508`) - :func:`merge_asof` now gives a more clear error message when merge keys are categoricals that are not equal (:issue:`26136`) +- :meth:`pandas.core.window.Rolling` supports exponential (or Poisson) window type (:issue:`21303`) .. _whatsnew_0250.api_breaking: diff --git a/pandas/core/window.py b/pandas/core/window.py index ffb88b9c4eb65..2d7fdbeffbccc 100644 --- a/pandas/core/window.py +++ b/pandas/core/window.py @@ -504,7 +504,8 @@ class Window(_Window): * ``kaiser`` (needs beta) * ``gaussian`` (needs std) * ``general_gaussian`` (needs power, width) - * ``slepian`` (needs width). + * ``slepian`` (needs width) + * ``exponential`` (needs tau), center is set to None. If ``win_type=None`` all points are evenly weighted. To learn more about different window types see `scipy.signal window functions @@ -623,11 +624,19 @@ def _validate_win_type(win_type, kwargs): arg_map = {'kaiser': ['beta'], 'gaussian': ['std'], 'general_gaussian': ['power', 'width'], - 'slepian': ['width']} + 'slepian': ['width'], + 'exponential': ['tau'], + } + if win_type in arg_map: - return tuple([win_type] + _pop_args(win_type, - arg_map[win_type], - kwargs)) + win_args = _pop_args(win_type, arg_map[win_type], kwargs) + if win_type == 'exponential': + # exponential window requires the first arg (center) + # to be set to None (necessary for symmetric window) + win_args.insert(0, None) + + return tuple([win_type] + win_args) + return win_type def _pop_args(win_type, arg_names, kwargs): diff --git a/pandas/tests/test_window.py b/pandas/tests/test_window.py index 1d5dd8c2bfcf8..bc6946cbade4c 100644 --- a/pandas/tests/test_window.py +++ b/pandas/tests/test_window.py @@ -42,7 +42,8 @@ def win_types(request): return request.param -@pytest.fixture(params=['kaiser', 'gaussian', 'general_gaussian']) +@pytest.fixture(params=['kaiser', 'gaussian', 'general_gaussian', + 'exponential']) def win_types_special(request): return request.param @@ -1260,7 +1261,8 @@ def test_cmov_window_special(self, win_types_special): kwds = { 'kaiser': {'beta': 1.}, 'gaussian': {'std': 1.}, - 'general_gaussian': {'power': 2., 'width': 2.}} + 'general_gaussian': {'power': 2., 'width': 2.}, + 'exponential': {'tau': 10}} vals = np.array([6.95, 15.21, 4.72, 9.12, 13.81, 13.49, 16.68, 9.48, 10.63, 14.48]) @@ -1271,7 +1273,9 @@ def test_cmov_window_special(self, win_types_special): 'general_gaussian': [np.nan, np.nan, 9.85011, 10.71589, 11.73161, 13.08516, 12.95111, 12.74577, np.nan, np.nan], 'kaiser': [np.nan, np.nan, 9.86851, 11.02969, 11.65161, 12.75129, - 12.90702, 12.83757, np.nan, np.nan] + 12.90702, 12.83757, np.nan, np.nan], + 'exponential': [np.nan, np.nan, 9.83364, 11.10472, 11.64551, + 12.66138, 12.92379, 12.83770, np.nan, np.nan], } xp = Series(xps[win_types_special]) @@ -1287,7 +1291,8 @@ def test_cmov_window_special_linear_range(self, win_types_special): 'kaiser': {'beta': 1.}, 'gaussian': {'std': 1.}, 'general_gaussian': {'power': 2., 'width': 2.}, - 'slepian': {'width': 0.5}} + 'slepian': {'width': 0.5}, + 'exponential': {'tau': 10}} vals = np.array(range(10), dtype=np.float) xp = vals.copy()