diff --git a/pandas/stats/moments.py b/pandas/stats/moments.py index 586d507b27493..70b6bcb5c4de9 100644 --- a/pandas/stats/moments.py +++ b/pandas/stats/moments.py @@ -122,7 +122,7 @@ When ignore_na is True (reproducing pre-0.15.0 behavior), weights are based on relative positions. For example, the weights of x and y used in calculating -the final weighted average of [x, None, y] are 1-alpha and 1 (if adjust is +the final weighted average of [x, None, y] are 1-alpha and 1 (if adjust is True), and 1-alpha and alpha (if adjust is False). """ @@ -399,7 +399,7 @@ def _rolling_moment(arg, window, func, minp, axis=0, freq=None, center=False, if center: result = _center_window(result, window, axis) - + return return_hook(result) @@ -1036,3 +1036,125 @@ def expanding_apply(arg, func, min_periods=1, freq=None, window = max(len(arg), min_periods) if min_periods else len(arg) return rolling_apply(arg, window, func, min_periods=min_periods, freq=freq, args=args, kwargs=kwargs) + +#---------------------------------------------------------------------- +# Add all the methods to DataFrame and Series +import sys +thismodule = sys.modules[__name__] + +from pandas.core.base import AccessorProperty +from functools import update_wrapper +from pandas.core import common as com +from pandas.core.base import PandasDelegate + + +RollingMethods = type( + "RollingMethods", + (), + { + fct_name.replace("rolling_", ""): staticmethod( + getattr(thismodule, fct_name) + ) + for fct_name in __all__ + if fct_name.startswith("rolling_") + } +) + +ExpandingMethods = type( + "ExpandingMethods", + (), + { + fct_name.replace("expanding_", ""): staticmethod( + getattr(thismodule, fct_name) + ) + for fct_name in __all__ + if fct_name.startswith("expanding_") + } +) + +EwmMethods = type( + "EwmMethods", + (), + { + fct_name.replace("ewm", ""): staticmethod( + getattr(thismodule, fct_name) + ) + for fct_name in __all__ + if fct_name.startswith("ewm") + } +) + +class MomentDelegator(PandasDelegate): + prefix = None + klass = None + + def __init__(self, series, prefix, klass): + self.series = series + def _delegate_method(self, name, *args, **kwargs): + method = getattr(self.klass, name) + return method(self.series, *args, **kwargs) + + @classmethod + def generate_make_moment_accessor(cls): + prefix = cls.prefix + klass = cls.klass + def moment_rolling_accessor(self): + check_dtype(self, prefix) + return cls(self, prefix, klass) + return moment_rolling_accessor + +class RollingDelegator(MomentDelegator): + prefix = "rolling_" + klass = RollingMethods + +RollingDelegator._add_delegate_accessors( + delegate=RollingMethods, + accessors=RollingMethods.__dict__.keys(), + typ='method' +) + +class ExpandingDelegator(MomentDelegator): + prefix = "expanding_" + klass = ExpandingMethods + +ExpandingDelegator._add_delegate_accessors( + delegate=ExpandingMethods, + accessors=ExpandingMethods.__dict__.keys(), + typ='method' +) + +class EwmDelegator(MomentDelegator): + prefix = "ewm" + klass = EwmMethods + +EwmDelegator._add_delegate_accessors( + delegate=EwmMethods, + accessors=EwmMethods.__dict__.keys(), + typ='method' +) + +def check_dtype(self, name): + if isinstance(self, Series) \ + and not ( + com.is_float_dtype(self.dtype) + or + com.is_integer_dtype(self.dtype) + ): + raise AttributeError( + "Can only use .{} accessor with floats or int values".format(name) + ) + if isinstance(self, DataFrame) \ + and not True in [ # check whether there is one dtype float or integer + com.is_float_dtype(t) or com.is_integer_dtype(t) + for t in self.dtypes]: + raise AttributeError( + "Can only use .{}".format(name) + + " accessor if there exist at least one column of dtype floats or int" + ) + +DataFrame.rolling = AccessorProperty(RollingDelegator, RollingDelegator.generate_make_moment_accessor()) +DataFrame.expanding = AccessorProperty(ExpandingDelegator, ExpandingDelegator.generate_make_moment_accessor()) +DataFrame.ewm = AccessorProperty(EwmDelegator, EwmDelegator.generate_make_moment_accessor()) +Series.rolling = AccessorProperty(RollingDelegator, RollingDelegator.generate_make_moment_accessor()) +Series.expanding = AccessorProperty(ExpandingDelegator, ExpandingDelegator.generate_make_moment_accessor()) +Series.ewm = AccessorProperty(EwmDelegator, EwmDelegator.generate_make_moment_accessor())