{"action":"created","comment":{"url":"https://api.github.com/repos/pydata/pandas/pulls/comments/47635115","id":47635115,"diff_hunk":"@@ -0,0 +1,1361 @@\n+\"\"\"\n+\n+provide a generic structure to support window functions,\n+similar to how we have a Groupby object\n+\n+\n+\"\"\"\n+from __future__ import division\n+\n+import warnings\n+import numpy as np\n+from functools import wraps\n+from collections import defaultdict\n+\n+import pandas as pd\n+from pandas.lib import isscalar\n+from pandas.core.base import PandasObject, SelectionMixin, AbstractMethodError\n+import pandas.core.common as com\n+import pandas.algos as algos\n+from pandas import compat\n+from pandas.util.decorators import Substitution, Appender\n+from textwrap import dedent\n+\n+_shared_docs = dict()\n+_doc_template = \"\"\"\n+\n+Returns\n+-------\n+same type as input\n+\n+See also\n+--------\n+`pandas.Series.%(name)s`\n+`pandas.DataFrame.%(name)s`\n+\"\"\"\n+\n+class _Window(PandasObject, SelectionMixin):\n+    _attributes = ['window','min_periods','freq','center','win_type','axis']\n+    exclusions = set()\n+\n+    def __init__(self, obj, window=None, min_periods=None, freq=None, center=False,\n+                 win_type=None, axis=0):\n+\n+        if freq is not None:\n+            warnings.warn(\"The freq kw is deprecated and will be removed in a future version. You can resample prior \"\n+                          \"to passing to a window function\",\n+                          FutureWarning, stacklevel=3)\n+\n+        self.blocks = []\n+        self.obj = obj\n+        self.window = window\n+        self.min_periods = min_periods\n+        self.freq = freq\n+        self.center = center\n+        self.win_type = win_type\n+        self.axis = axis\n+        self._setup()\n+\n+    @property\n+    def _constructor(self):\n+        return Window\n+\n+    def _setup(self):\n+        pass\n+\n+    def _convert_freq(self, how=None):\n+        \"\"\" resample according to the how, return a new object \"\"\"\n+        obj = self._selected_obj\n+        if self.freq is not None and isinstance(obj, (com.ABCSeries, com.ABCDataFrame)):\n+            obj = obj.resample(self.freq, how=how)\n+        return obj\n+\n+    def _create_blocks(self, how):\n+        \"\"\" split data into blocks & return conformed data \"\"\"\n+\n+        obj = self._convert_freq(how)\n+        return obj.as_blocks(copy=False).values(), obj\n+\n+    def _gotitem(self, key, ndim, subset=None):\n+        \"\"\"\n+        sub-classes to define\n+        return a sliced object\n+\n+        Parameters\n+        ----------\n+        key : string / list of selections\n+        ndim : 1,2\n+            requested ndim of result\n+        subset : object, default None\n+            subset to act on\n+        \"\"\"\n+\n+        # create a new object to prevent aliasing\n+        if subset is None:\n+            subset = self.obj\n+        self = self._shallow_copy(subset)\n+        self._reset_cache()\n+        if subset.ndim==2:\n+            if isscalar(key) and key in subset or com.is_list_like(key):\n+                self._selection = key\n+        return self\n+\n+    def __getattr__(self, attr):\n+        if attr in self._internal_names_set:\n+            return object.__getattribute__(self, attr)\n+        if attr in self.obj:\n+            return self[attr]\n+\n+        raise AttributeError(\"%r object has no attribute %r\" %\n+                             (type(self).__name__, attr))\n+\n+    def _dir_additions(self):\n+        return self.obj._dir_additions()\n+\n+    def _get_window(self, other=None):\n+        return self.window\n+\n+    def __unicode__(self):\n+        \"\"\" provide a nice str repr of our rolling object \"\"\"\n+\n+        attrs = [ \"{k}->{v}\".format(k=k,v=getattr(self,k)) \\\n+                  for k in self._attributes if getattr(self,k,None) is not None ]\n+        return \"{klass} [{attrs}]\".format(klass=self.__class__.__name__,\n+                                          attrs=','.join(attrs))\n+\n+    def _shallow_copy(self, obj=None, **kwargs):\n+        \"\"\" return a new object with the replacement attributes \"\"\"\n+        if obj is None:\n+            obj = self._selected_obj.copy()\n+        if isinstance(obj, self.__class__):\n+            obj = obj.obj\n+        for attr in self._attributes:\n+            if attr not in kwargs:\n+                kwargs[attr] = getattr(self,attr)\n+        return self._constructor(obj, **kwargs)\n+\n+    def _prep_values(self, values=None, kill_inf=True, how=None):\n+\n+        if values is None:\n+            values = getattr(self._selected_obj,'values',self._selected_obj)\n+\n+        # coerce dtypes as appropriate\n+        if com.is_float_dtype(values.dtype):\n+            pass\n+        elif com.is_integer_dtype(values.dtype):\n+            values = values.astype(float)\n+        elif com.is_timedelta64_dtype(values.dtype):\n+            values = values.view('i8').astype(float)\n+        else:\n+            try:\n+                values = values.astype(float)\n+            except (ValueError, TypeError):\n+                raise TypeError(\"cannot handle this type -> {0}\".format(values.dtype))\n+\n+        if kill_inf:\n+            values = values.copy()\n+            values[np.isinf(values)] = np.NaN\n+\n+        return values\n+\n+    def _wrap_result(self, result, block=None, obj=None):\n+        \"\"\" wrap a single result \"\"\"\n+\n+        if obj is None:\n+            obj = self._selected_obj\n+        if isinstance(result, np.ndarray):\n+\n+            # coerce if necessary\n+            if block is not None:\n+                if com.is_timedelta64_dtype(block.values.dtype):\n+                    result = pd.to_timedelta(result.ravel(),unit='ns').values.reshape(result.shape)\n+\n+            if result.ndim == 1:\n+                from pandas import Series\n+                return Series(result, obj.index, name=obj.name)\n+\n+            return type(obj)(result,\n+                             index=obj.index,\n+                             columns=block.columns)\n+        return result\n+\n+    def _wrap_results(self, results, blocks, obj):\n+        \"\"\"\n+        wrap the results\n+\n+        Paramters\n+        ---------\n+        results : list of ndarrays\n+        blocks : list of blocks\n+        obj : conformed data (may be resampled)\n+        \"\"\"\n+\n+        final = []\n+        for result, block in zip(results, blocks):\n+\n+            result = self._wrap_result(result, block=block, obj=obj)\n+            if result.ndim == 1:\n+                return result\n+            final.append(result)\n+\n+        if not len(final):\n+            return obj.astype('float64')\n+        return pd.concat(final,axis=1).reindex(columns=obj.columns)\n+\n+    def _center_window(self, result, window):\n+        \"\"\" center the result in the window \"\"\"\n+        if self.axis > result.ndim-1:\n+            raise ValueError(\"Requested axis is larger then no. of argument \"\n+                             \"dimensions\")\n+\n+        from pandas import Series, DataFrame\n+        offset = _offset(window, True)\n+        if offset > 0:\n+            if isinstance(result, (Series, DataFrame)):\n+                result = result.slice_shift(-offset, axis=self.axis)\n+            else:\n+                lead_indexer = [slice(None)] * result.ndim\n+                lead_indexer[self.axis] = slice(offset, None)\n+                result = np.copy(result[tuple(lead_indexer)])\n+        return result\n+\n+    def aggregate(self, arg, *args, **kwargs):\n+        result, how = self._aggregate(arg, *args, **kwargs)\n+        if result is None:\n+            return self.apply(arg, args=args, kwargs=kwargs)\n+        return result\n+\n+    agg = aggregate\n+\n+class Window(_Window):\n+    \"\"\"\n+    Provides rolling transformations.\n+\n+    .. versionadded:: 0.18.0\n+\n+    Parameters\n+    ----------\n+    window : int\n+       Size of the moving window. This is the number of observations used for\n+       calculating the statistic.\n+    min_periods : int, default None\n+        Minimum number of observations in window required to have a value\n+        (otherwise result is NA).\n+    freq : string or DateOffset object, optional (default None)\n+        Frequency to conform the data to before computing the statistic. Specified\n+        as a frequency string or DateOffset object.\n+    center : boolean, default False\n+        Set the labels at the center of the window.\n+    win_type : string, default None\n+        prove a window type, see the notes below\n+    axis : int, default 0\n+\n+    Returns\n+    -------\n+    a Window sub-classed for the particular operation\n+\n+    Notes\n+    -----\n+    By default, the result is set to the right edge of the window. This can be\n+    changed to the center of the window by setting ``center=True``.\n+\n+    The `freq` keyword is used to conform time series data to a specified\n+    frequency by resampling the data. This is done with the default parameters\n+    of :meth:`~pandas.Series.resample` (i.e. using the `mean`).\n+\n+    The recognized window types are:\n+\n+    * ``boxcar``\n+    * ``triang``\n+    * ``blackman``\n+    * ``hamming``\n+    * ``bartlett``\n+    * ``parzen``\n+    * ``bohman``\n+    * ``blackmanharris``\n+    * ``nuttall``\n+    * ``barthann``\n+    * ``kaiser`` (needs beta)\n+    * ``gaussian`` (needs std)\n+    * ``general_gaussian`` (needs power, width)\n+    * ``slepian`` (needs width).\n+\"\"\"\n+\n+    def _prep_window(self, **kwargs):\n+        \"\"\" provide validation for our window type, return the window \"\"\"\n+        window = self._get_window()\n+\n+        if isinstance(window, (list, tuple, np.ndarray)):\n+            return com._asarray_tuplesafe(window).astype(float)\n+        elif com.is_integer(window):\n+            try:\n+                import scipy.signal as sig\n+            except ImportError:\n+                raise ImportError('Please install scipy to generate window weight')\n+            win_type = _validate_win_type(self.win_type, kwargs)  # may pop from kwargs\n+            return sig.get_window(win_type, window).astype(float)\n+\n+        raise ValueError('Invalid window %s' % str(window))\n+\n+    def _apply_window(self, mean=True, how=None, **kwargs):\n+        \"\"\"\n+        Applies a moving window of type ``window_type`` on the data.\n+\n+        Parameters\n+        ----------\n+        mean : boolean, default True\n+            If True computes weighted mean, else weighted sum\n+        how : string, default to None (DEPRECATED)\n+            how to resample\n+\n+        Returns\n+        -------\n+        y : type of input argument\n+\n+        \"\"\"\n+        window = self._prep_window(**kwargs)\n+        center = self.center\n+\n+        blocks, obj = self._create_blocks(how=how)\n+        results = []\n+        for b in blocks:\n+            try:\n+                values = self._prep_values(b.values)\n+            except TypeError:\n+                results.append(b.values.copy())\n+                continue\n+\n+            if values.size == 0:\n+                results.append(values.copy())\n+                continue\n+\n+            offset = _offset(window, center)\n+            additional_nans = np.array([np.NaN] * offset)\n+            def f(arg, *args, **kwargs):\n+                minp = _use_window(self.min_periods, len(window))\n+                return algos.roll_window(np.concatenate((arg, additional_nans)) if center else arg,\n+                                         window, minp, avg=mean)\n+\n+            result = np.apply_along_axis(f, self.axis, values)\n+\n+            if center:\n+                result = self._center_window(result, window)\n+            results.append(result)\n+\n+        return self._wrap_results(results, blocks, obj)\n+\n+    @Substitution(name='rolling')\n+    @Appender(SelectionMixin._agg_doc)\n+    @Appender(SelectionMixin._see_also_template)\n+    def aggregate(self, arg, *args, **kwargs):\n+        result, how = self._aggregate(arg, *args, **kwargs)\n+        if result is None:\n+\n+            # these must apply directly\n+            result = arg(self)\n+\n+        return result\n+\n+    agg = aggregate\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    def sum(self, **kwargs):\n+        return self._apply_window(mean=False, **kwargs)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    def mean(self, **kwargs):\n+        return self._apply_window(mean=True, **kwargs)\n+\n+class _Rolling(_Window):\n+\n+    @property\n+    def _constructor(self):\n+        return Rolling\n+\n+    def _apply(self, func, window=None, center=None, check_minp=None, how=None, **kwargs):\n+        \"\"\"\n+        Rolling statistical measure using supplied function. Designed to be\n+        used with passed-in Cython array-based functions.\n+\n+        Parameters\n+        ----------\n+        func : string/callable to apply\n+        window : int/array, default to _get_window()\n+        center : boolean, default to self.center\n+        check_minp : function, default to _use_window\n+        how : string, default to None (DEPRECATED)\n+            how to resample\n+\n+        Returns\n+        -------\n+        y : type of input\n+        \"\"\"\n+        if center is None:\n+            center = self.center\n+        if window is None:\n+            window = self._get_window()\n+\n+        if check_minp is None:\n+            check_minp = _use_window\n+\n+        blocks, obj = self._create_blocks(how=how)\n+        results = []\n+        for b in blocks:\n+            try:\n+                values = self._prep_values(b.values)\n+            except TypeError:\n+                results.append(b.values.copy())\n+                continue\n+\n+            if values.size == 0:\n+                results.append(values.copy())\n+                continue\n+\n+            # if we have a string function name, wrap it\n+            if isinstance(func, compat.string_types):\n+                if not hasattr(algos, func):\n+                    raise ValueError(\"we do not support this function algos.{0}\".format(func))\n+\n+                cfunc = getattr(algos, func)\n+                def func(arg, window, min_periods=None):\n+                    minp = check_minp(min_periods, window)\n+                    return cfunc(arg, window, minp, **kwargs)\n+\n+            # calculation function\n+            if center:\n+                offset = _offset(window, center)\n+                additional_nans = np.array([np.NaN] * offset)\n+                def calc(x):\n+                    return func(np.concatenate((x, additional_nans)),\n+                                window, min_periods=self.min_periods)\n+            else:\n+                def calc(x):\n+                    return func(x,window, min_periods=self.min_periods)\n+\n+            if values.ndim > 1:\n+                result = np.apply_along_axis(calc, self.axis, values)\n+            else:\n+                result = calc(values)\n+\n+            if center:\n+                result = self._center_window(result, window)\n+\n+            results.append(result)\n+\n+        return self._wrap_results(results, blocks, obj)\n+\n+class _Rolling_and_Expanding(_Rolling):\n+\n+    _shared_docs['count'] = \"\"\"%(name)s count of number of non-NaN observations inside provided window.\"\"\"\n+    def count(self):\n+        obj = self._convert_freq()\n+        window = self._get_window()\n+        window = min(window, len(obj)) if not self.center else window\n+        try:\n+            converted = np.isfinite(obj).astype(float)\n+        except TypeError:\n+            converted = np.isfinite(obj.astype(float)).astype(float)\n+        result = self._constructor(converted,\n+                                   window=window,\n+                                   min_periods=0,\n+                                   center=self.center).sum()\n+\n+        result[result.isnull()] = 0\n+        return result\n+\n+    _shared_docs['apply'] = dedent(\"\"\"\n+    %(name)s function apply\n+\n+    Parameters\n+    ----------\n+    func : function\n+    Must produce a single value from an ndarray input\n+    *args and **kwargs are passed to the function\"\"\")\n+\n+    def apply(self, func, args=(), kwargs={}):\n+        _level = kwargs.pop('_level',None)\n+        window = self._get_window()\n+        offset = _offset(window, self.center)\n+        def f(arg, window, min_periods):\n+            minp = _use_window(min_periods, window)\n+            return algos.roll_generic(arg, window, minp, offset, func, args, kwargs)\n+\n+        return self._apply(f, center=False)\n+\n+    _shared_docs['sum'] = \"\"\"%(name)s sum\"\"\"\n+    def sum(self):\n+        return self._apply('roll_sum')\n+\n+    _shared_docs['max'] = dedent(\"\"\"\n+    %(name)s maximum\n+\n+    Parameters\n+    ----------\n+    how : string, default 'max' (DEPRECATED)\n+    Method for down- or re-sampling\"\"\")\n+    def max(self, how=None):\n+        if how is not None:\n+            warnings.warn(\"The how kw argument is deprecated and removed in a future version. You can resample prior \"\n+                          \"to passing to a window function\",\n+                          FutureWarning, stacklevel=3)\n+        else:\n+            how = 'max'\n+        return self._apply('roll_max', how=how)\n+\n+    _shared_docs['min'] = dedent(\"\"\"\n+    %(name)s minimum\n+\n+    Parameters\n+    ----------\n+    how : string, default 'min' (DEPRECATED)\n+    Method for down- or re-sampling\"\"\")\n+    def min(self, how=None):\n+        if how is not None:\n+            warnings.warn(\"The how kw argument is deprecated and removed in a future version. You can resample prior \"\n+                          \"to passing to a window function\",\n+                          FutureWarning, stacklevel=3)\n+        else:\n+            how = 'min'\n+        return self._apply('roll_min', how=how)\n+\n+    _shared_docs['mean'] = \"\"\"%(name)s mean\"\"\"\n+    def mean(self):\n+        return self._apply('roll_mean')\n+\n+    _shared_docs['median'] = dedent(\"\"\"\n+    %(name)s median\n+\n+    Parameters\n+    ----------\n+    how : string, default 'median' (DEPRECATED)\n+    Method for down- or re-sampling\"\"\")\n+    def median(self, how=None):\n+        if how is not None:\n+            warnings.warn(\"The how kw argument is deprecated and removed in a future version. You can resample prior \"\n+                          \"to passing to a window function\",\n+                          FutureWarning, stacklevel=3)\n+        else:\n+            how = 'median'\n+        return self._apply('roll_median_c', how=how)\n+\n+    _shared_docs['std'] = dedent(\"\"\"\n+    %(name)s standard deviation\n+\n+    Parameters\n+    ----------\n+    ddof : int, default 1\n+    Delta Degrees of Freedom.  The divisor used in calculations\n+    is ``N - ddof``, where ``N`` represents the number of elements.\"\"\")\n+\n+    def std(self, ddof=1):\n+        window = self._get_window()\n+        def f(arg, *args, **kwargs):\n+            minp = _require_min_periods(1)(self.min_periods, window)\n+            return _zsqrt(algos.roll_var(arg, window, minp, ddof))\n+\n+        return self._apply(f, check_minp=_require_min_periods(1))\n+\n+    _shared_docs['var'] = dedent(\"\"\"\n+    %(name)s variance\n+\n+    Parameters\n+    ----------\n+    ddof : int, default 1\n+    Delta Degrees of Freedom.  The divisor used in calculations\n+    is ``N - ddof``, where ``N`` represents the number of elements.\"\"\")\n+\n+    def var(self, ddof=1):\n+        return self._apply('roll_var',\n+                           check_minp=_require_min_periods(1),\n+                           ddof=ddof)\n+\n+    _shared_docs['skew'] = \"\"\"Unbiased %(name)s skewness\"\"\"\n+    def skew(self):\n+        return self._apply('roll_skew',\n+                           check_minp=_require_min_periods(3))\n+\n+    _shared_docs['kurt'] = \"\"\"Unbiased %(name)s kurtosis\"\"\"\n+    def kurt(self):\n+        return self._apply('roll_kurt',\n+                           check_minp=_require_min_periods(4))\n+\n+    _shared_docs['quantile'] = dedent(\"\"\"\n+    %(name)s quantile\n+\n+    Parameters\n+    ----------\n+    quantile : float\n+    0 <= quantile <= 1\"\"\")\n+\n+    def quantile(self, quantile):\n+        window = self._get_window()\n+        def f(arg, *args, **kwargs):\n+            minp = _use_window(self.min_periods, window)\n+            return algos.roll_quantile(arg, window, minp, quantile)\n+\n+        return self._apply(f)\n+\n+    _shared_docs['cov'] = dedent(\"\"\"\n+    %(name)s sample covariance\n+\n+    Parameters\n+    ----------\n+    other : Series, DataFrame, or ndarray, optional\n+        if not supplied then will default to self and produce pairwise output\n+    pairwise : bool, default None\n+        If False then only matching columns between self and other will be used and\n+        the output will be a DataFrame.\n+        If True then all pairwise combinations will be calculated and the output\n+        will be a Panel in the case of DataFrame inputs. In the case of missing\n+        elements, only complete pairwise observations will be used.\n+    ddof : int, default 1\n+        Delta Degrees of Freedom.  The divisor used in calculations\n+        is ``N - ddof``, where ``N`` represents the number of elements.\"\"\")\n+\n+    def cov(self, other=None, pairwise=None, ddof=1):\n+        if other is None:\n+            other = self._selected_obj\n+            pairwise = True if pairwise is None else pairwise  # only default unset\n+        other = self._shallow_copy(other)\n+        window = self._get_window(other)\n+\n+        def _get_cov(X, Y):\n+            mean = lambda x: x.rolling(window, self.min_periods, center=self.center).mean()\n+            count = (X+Y).rolling(window=window, center=self.center).count()\n+            bias_adj = count / (count - ddof)\n+            return (mean(X * Y) - mean(X) * mean(Y)) * bias_adj\n+        return _flex_binary_moment(self._selected_obj, other._selected_obj, _get_cov, pairwise=bool(pairwise))\n+\n+    _shared_docs['corr'] = dedent(\"\"\"\n+    %(name)s sample correlation\n+\n+    Parameters\n+    ----------\n+    other : Series, DataFrame, or ndarray, optional\n+        if not supplied then will default to self and produce pairwise output\n+    pairwise : bool, default None\n+        If False then only matching columns between self and other will be used and\n+        the output will be a DataFrame.\n+        If True then all pairwise combinations will be calculated and the output\n+        will be a Panel in the case of DataFrame inputs. In the case of missing\n+        elements, only complete pairwise observations will be used.\"\"\")\n+\n+    def corr(self, other=None, pairwise=None):\n+        if other is None:\n+            other = self._selected_obj\n+            pairwise = True if pairwise is None else pairwise  # only default unset\n+        other = self._shallow_copy(other)\n+        window = self._get_window(other)\n+\n+        def _get_corr(a, b):\n+            a = a.rolling(window=window,\n+                          min_periods=self.min_periods,\n+                          freq=self.freq,\n+                          center=self.center)\n+            b = b.rolling(window=window,\n+                          min_periods=self.min_periods,\n+                          freq=self.freq,\n+                          center=self.center)\n+\n+            return a.cov(b) / (a.std() * b.std())\n+        return _flex_binary_moment(self._selected_obj, other._selected_obj, _get_corr, pairwise=bool(pairwise))\n+\n+class Rolling(_Rolling_and_Expanding):\n+    \"\"\"\n+    Provides rolling transformations.\n+\n+    .. versionadded:: 0.18.0\n+\n+    Parameters\n+    ----------\n+    window : int\n+        Size of the moving window. This is the number of observations used for\n+        calculating the statistic.\n+    min_periods : int, default None\n+        Minimum number of observations in window required to have a value\n+        (otherwise result is NA).\n+    freq : string or DateOffset object, optional (default None) (DEPRECATED)\n+        Frequency to conform the data to before computing the statistic. Specified\n+        as a frequency string or DateOffset object.\n+    center : boolean, default False\n+        Set the labels at the center of the window.\n+    axis : int, default 0\n+\n+    Returns\n+    -------\n+    a Window sub-classed for the particular operation\n+\n+    Notes\n+    -----\n+    By default, the result is set to the right edge of the window. This can be\n+    changed to the center of the window by setting ``center=True``.\n+\n+    The `freq` keyword is used to conform time series data to a specified\n+    frequency by resampling the data. This is done with the default parameters\n+    of :meth:`~pandas.Series.resample` (i.e. using the `mean`).\n+    \"\"\"\n+\n+    @Substitution(name='rolling')\n+    @Appender(SelectionMixin._agg_doc)\n+    @Appender(SelectionMixin._see_also_template)\n+    def aggregate(self, arg, *args, **kwargs):\n+        return super(Rolling, self).aggregate(arg, *args, **kwargs)\n+\n+    agg = aggregate\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['count'])\n+    def count(self):\n+        return super(Rolling, self).count()\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['apply'])\n+    def apply(self, func, args=(), kwargs={}):\n+        return super(Rolling, self).apply(func, args=args, kwargs=kwargs)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['sum'])\n+    def sum(self):\n+        return super(Rolling, self).sum()\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['max'])\n+    def max(self, **kwargs):\n+        return super(Rolling, self).max(**kwargs)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['min'])\n+    def min(self, **kwargs):\n+        return super(Rolling, self).min(**kwargs)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['mean'])\n+    def mean(self):\n+        return super(Rolling, self).mean()\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['median'])\n+    def median(self, **kwargs):\n+        return super(Rolling, self).median(**kwargs)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['std'])\n+    def std(self, ddof=1):\n+        return super(Rolling, self).std(ddof=ddof)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['var'])\n+    def var(self, ddof=1):\n+        return super(Rolling, self).var(ddof=ddof)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['skew'])\n+    def skew(self):\n+        return super(Rolling, self).skew()\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['kurt'])\n+    def kurt(self):\n+        return super(Rolling, self).kurt()\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['quantile'])\n+    def quantile(self, quantile):\n+        return super(Rolling, self).quantile(quantile=quantile)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['cov'])\n+    def cov(self, other=None, pairwise=None, ddof=1):\n+        return super(Rolling, self).cov(other=other, pairwise=pairwise, ddof=ddof)\n+\n+    @Substitution(name='rolling')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['corr'])\n+    def corr(self, other=None, pairwise=None):\n+        return super(Rolling, self).corr(other=other, pairwise=pairwise)\n+\n+class Expanding(_Rolling_and_Expanding):\n+    \"\"\"\n+    Provides expanding transformations.\n+\n+    .. versionadded:: 0.18.0\n+\n+    Parameters\n+    ----------\n+    min_periods : int, default None\n+        Minimum number of observations in window required to have a value\n+        (otherwise result is NA).\n+    freq : string or DateOffset object, optional (default None) (DEPRECATED)\n+        Frequency to conform the data to before computing the statistic. Specified\n+        as a frequency string or DateOffset object.\n+    center : boolean, default False\n+        Set the labels at the center of the window.\n+    axis : int, default 0\n+\n+    Returns\n+    -------\n+    a Window sub-classed for the particular operation\n+\n+    Notes\n+    -----\n+    By default, the result is set to the right edge of the window. This can be\n+    changed to the center of the window by setting ``center=True``.\n+\n+    The `freq` keyword is used to conform time series data to a specified\n+    frequency by resampling the data. This is done with the default parameters\n+    of :meth:`~pandas.Series.resample` (i.e. using the `mean`).\n+    \"\"\"\n+\n+    _attributes = ['min_periods','freq','center','axis']\n+\n+    def __init__(self, obj, min_periods=1, freq=None, center=False, axis=0, **kwargs):\n+        return super(Expanding, self).__init__(obj=obj, min_periods=min_periods, freq=freq, center=center, axis=axis)\n+\n+    @property\n+    def _constructor(self):\n+        return Expanding\n+\n+    def _get_window(self, other=None):\n+        obj = self._selected_obj\n+        if other is None:\n+            return max(len(obj), self.min_periods) if self.min_periods else len(obj)\n+        return max((len(obj) + len(obj)), self.min_periods) if self.min_periods else (len(obj) + len(obj))\n+\n+    @Substitution(name='expanding')\n+    @Appender(SelectionMixin._agg_doc)\n+    @Appender(SelectionMixin._see_also_template)\n+    def aggregate(self, arg, *args, **kwargs):\n+        return super(Expanding, self).aggregate(arg, *args, **kwargs)\n+\n+    agg = aggregate\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['count'])\n+    def count(self):\n+        return super(Expanding, self).count()\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['apply'])\n+    def apply(self, func, args=(), kwargs={}):\n+        return super(Expanding, self).apply(func, args=args, kwargs=kwargs)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['sum'])\n+    def sum(self):\n+        return super(Expanding, self).sum()\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['max'])\n+    def max(self, **kwargs):\n+        return super(Expanding, self).max(**kwargs)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['min'])\n+    def min(self, **kwargs):\n+        return super(Expanding, self).min(**kwargs)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['mean'])\n+    def mean(self):\n+        return super(Expanding, self).mean()\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['median'])\n+    def median(self, **kwargs):\n+        return super(Expanding, self).median(**kwargs)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['std'])\n+    def std(self, ddof=1):\n+        return super(Expanding, self).std(ddof=ddof)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['var'])\n+    def var(self, ddof=1):\n+        return super(Expanding, self).var(ddof=ddof)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['skew'])\n+    def skew(self):\n+        return super(Expanding, self).skew()\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['kurt'])\n+    def kurt(self):\n+        return super(Expanding, self).kurt()\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['quantile'])\n+    def quantile(self, quantile):\n+        return super(Expanding, self).quantile(quantile=quantile)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['cov'])\n+    def cov(self, other=None, pairwise=None, ddof=1):\n+        return super(Expanding, self).cov(other=other, pairwise=pairwise, ddof=ddof)\n+\n+    @Substitution(name='expanding')\n+    @Appender(_doc_template)\n+    @Appender(_shared_docs['corr'])\n+    def corr(self, other=None, pairwise=None):\n+        return super(Expanding, self).corr(other=other, pairwise=pairwise)\n+\n+class EWM(_Rolling):\n+    \"\"\"\n+    Provides exponential weighted functions\n+\n+    .. versionadded:: 0.18.0\n+\n+    Parameters\n+    ----------\n+    com : float. optional\n+        Center of mass: :math:`\\alpha = 1 / (1 + com)`,\n+    span : float, optional\n+        Specify decay in terms of span, :math:`\\alpha = 2 / (span + 1)`\n+    halflife : float, optional\n+        Specify decay in terms of halflife, :math:`\\alpha = 1 - exp(log(0.5) / halflife)`\n+    min_periods : int, default 0\n+        Minimum number of observations in window required to have a value\n+        (otherwise result is NA).\n+    freq : None or string alias / date offset object, default=None (DEPRECATED)\n+        Frequency to conform to before computing statistic\n+    adjust : boolean, default True\n+        Divide by decaying adjustment factor in beginning periods to account for\n+        imbalance in relative weightings (viewing EWMA as a moving average)\n+    ignore_na : boolean, default False\n+        Ignore missing values when calculating weights;\n+        specify True to reproduce pre-0.15.0 behavior\n+\n+    Returns\n+    -------\n+    a Window sub-classed for the particular operation\n+\n+    Notes\n+    -----\n+    Either center of mass, span or halflife must be specified\n+\n+    EWMA is sometimes specified using a \"span\" parameter `s`, we have that the\n+    decay parameter :math:`\\alpha` is related to the span as\n+    :math:`\\alpha = 2 / (s + 1) = 1 / (1 + c)`\n+\n+    where `c` is the center of mass. Given a span, the associated center of mass is\n+    :math:`c = (s - 1) / 2`\n+\n+    So a \"20-day EWMA\" would have center 9.5.\n+\n+    The `freq` keyword is used to conform time series data to a specified\n+    frequency by resampling the data. This is done with the default parameters\n+    of :meth:`~pandas.Series.resample` (i.e. using the `mean`).\n+\n+    When adjust is True (default), weighted averages are calculated using weights\n+        (1-alpha)**(n-1), (1-alpha)**(n-2), ..., 1-alpha, 1.\n+\n+    When adjust is False, weighted averages are calculated recursively as:\n+       weighted_average[0] = arg[0];\n+       weighted_average[i] = (1-alpha)*weighted_average[i-1] + alpha*arg[i].\n+\n+    When ignore_na is False (default), weights are based on absolute positions.\n+    For example, the weights of x and y used in calculating the final weighted\n+    average of [x, None, y] are (1-alpha)**2 and 1 (if adjust is True), and\n+    (1-alpha)**2 and alpha (if adjust is False).\n+\n+    When ignore_na is True (reproducing pre-0.15.0 behavior), weights are based on\n+    relative positions. For example, the weights of x and y used in calculating\n+    the final weighted average of [x, None, y] are 1-alpha and 1 (if adjust is\n+    True), and 1-alpha and alpha (if adjust is False).\n+\n+    More details can be found at\n+    http://pandas.pydata.org/pandas-docs/stable/computation.html#exponentially-weighted-moment-functions\n+    \"\"\"\n+    _attributes = ['com','min_periods','freq','adjust','ignore_na','axis']\n+\n+    def __init__(self, obj, com=None, span=None, halflife=None, min_periods=0, freq=None,\n+                 adjust=True, ignore_na=False, axis=0):\n+        self.obj = obj\n+        self.com = _get_center_of_mass(com, span, halflife)\n+        self.min_periods = min_periods\n+        self.freq = freq\n+        self.adjust = adjust\n+        self.ignore_na = ignore_na\n+        self.axis = axis\n+\n+    @property\n+    def _constructor(self):\n+        return EWM\n+\n+    @Substitution(name='ewm')\n+    @Appender(SelectionMixin._agg_doc)\n+    @Appender(SelectionMixin._see_also_template)\n+    def aggregate(self, arg, *args, **kwargs):\n+        return super(EWM, self).aggregate(arg, *args, **kwargs)\n+\n+    agg = aggregate\n+\n+    def _apply(self, func, how=None, **kwargs):\n+        \"\"\"Rolling statistical measure using supplied function. Designed to be\n+        used with passed-in Cython array-based functions.\n+\n+        Parameters\n+        ----------\n+        func : string/callable to apply\n+        how : string, default to None (DEPRECATED)\n+            how to resample\n+\n+        Returns\n+        -------\n+        y : type of input argument\n+\n+        \"\"\"\n+        blocks, obj = self._create_blocks(how=how)\n+        results = []\n+        for b in blocks:\n+            try:\n+                values = self._prep_values(b.values)\n+            except TypeError:\n+                results.append(b.values.copy())\n+                continue\n+\n+            if values.size == 0:\n+                results.append(values.copy())\n+                continue\n+\n+            # if we have a string function name, wrap it\n+            if isinstance(func, compat.string_types):\n+                if not hasattr(algos, func):\n+                    raise ValueError(\"we do not support this function algos.{0}\".format(func))\n+\n+                cfunc = getattr(algos, func)\n+                def func(arg):\n+                    return cfunc(arg, self.com, int(self.adjust), int(self.ignore_na), int(self.min_periods))\n+\n+            results.append(np.apply_along_axis(func, self.axis, values))\n+\n+        return self._wrap_results(results, blocks, obj)\n+\n+    @Substitution(name='ewm')\n+    @Appender(_doc_template)\n+    def mean(self):\n+        \"\"\"exponential weighted moving average\"\"\"\n+        return self._apply('ewma')\n+\n+    @Substitution(name='ewm')\n+    @Appender(_doc_template)\n+    def std(self, bias=False):\n+        \"\"\"exponential weighted moving stddev\n+\n+        Parameters\n+        ----------\n+        bias : boolean, default False\n+           Use a standard estimation bias correction\n+        \"\"\"\n+        return _zsqrt(self.var(bias=bias))\n+    vol=std\n+\n+    @Substitution(name='ewm')\n+    @Appender(_doc_template)\n+    def var(self, bias=False):\n+        \"\"\"exponential weighted moving average\n+\n+        Parameters\n+        ----------\n+        bias : boolean, default False\n+           Use a standard estimation bias correction\n+        \"\"\"","path":"pandas/core/window.py","position":1091,"original_position":1091,"commit_id":"25584402f79536a962f1b989646b3229bad9815b","original_commit_id":"25584402f79536a962f1b989646b3229bad9815b","user":{"login":"jreback","id":953992,"avatar_url":"https://avatars.githubusercontent.com/u/953992?v=3","gravatar_id":"","url":"https://api.github.com/users/jreback","html_url":"https://github.com/jreback","followers_url":"https://api.github.com/users/jreback/followers","following_url":"https://api.github.com/users/jreback/following{/other_user}","gists_url":"https://api.github.com/users/jreback/gists{/gist_id}","starred_url":"https://api.github.com/users/jreback/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jreback/subscriptions","organizations_url":"https://api.github.com/users/jreback/orgs","repos_url":"https://api.github.com/users/jreback/repos","events_url":"https://api.github.com/users/jreback/events{/privacy}","received_events_url":"https://api.github.com/users/jreback/received_events","type":"User","site_admin":false},"body":"done, had to move them to templates","created_at":"2015-12-15T13:29:04Z","updated_at":"2015-12-15T13:29:04Z","html_url":"https://github.com/pydata/pandas/pull/11603#discussion_r47635115","pull_request_url":"https://api.github.com/repos/pydata/pandas/pulls/11603","_links":{"self":{"href":"https://api.github.com/repos/pydata/pandas/pulls/comments/47635115"},"html":{"href":"https://github.com/pydata/pandas/pull/11603#discussion_r47635115"},"pull_request":{"href":"https://api.github.com/repos/pydata/pandas/pulls/11603"}}},"pull_request":{"url":"https://api.github.com/repos/pydata/pandas/pulls/11603","id":50728632,"html_url":"https://github.com/pydata/pandas/pull/11603","diff_url":"https://github.com/pydata/pandas/pull/11603.diff","patch_url":"https://github.com/pydata/pandas/pull/11603.patch","issue_url":"https://api.github.com/repos/pydata/pandas/issues/11603","number":11603,"state":"open","locked":false,"title":"API: provide Rolling/Expanding/EWM objects for deferred rolling type calculations #10702","user":{"login":"jreback","id":953992,"avatar_url":"https://avatars.githubusercontent.com/u/953992?v=3","gravatar_id":"","url":"https://api.github.com/users/jreback","html_url":"https://github.com/jreback","followers_url":"https://api.github.com/users/jreback/followers","following_url":"https://api.github.com/users/jreback/following{/other_user}","gists_url":"https://api.github.com/users/jreback/gists{/gist_id}","starred_url":"https://api.github.com/users/jreback/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jreback/subscriptions","organizations_url":"https://api.github.com/users/jreback/orgs","repos_url":"https://api.github.com/users/jreback/repos","events_url":"https://api.github.com/users/jreback/events{/privacy}","received_events_url":"https://api.github.com/users/jreback/received_events","type":"User","site_admin":false},"body":"closes #10702 \r\ncloses #9052\r\nxref #4950, removal of depr\r\n \r\nSo this basically takes all of the ``pd.rolling_*``,``pd.expanding_*``,``pd.ewma_*`` routines and allows an object oriented interface, similar to groupby.\r\n\r\nSome benefits:\r\n\r\n- nice tab completions on the Rolling/Expanding/EWM objects\r\n- much cleaner code internally\r\n- complete back compat, e.g. everything just works like it did\r\n- added a ``.agg/aggregate`` function, similar to groupby, where you can do multiple aggregations at once\r\n- added ``__getitem__`` accessing, e.g. ``df.rolling(....)['A','B'].sum()`` for a nicer API\r\n- allows for much of #8659  to be done very easily\r\n- fix for coercing Timedeltas properly\r\n- handling nuiscance (string) columns\r\n\r\nOther:\r\n- along with window doc rewrite, fixed doc-strings for groupby/window to provide back-refs\r\n\r\nToDO:\r\n- [x] I think that all of the doc-strings are correct, but need check\r\n- [x] implement ``.agg``\r\n- [x] update API.rst, what's new\r\n- [x] deprecate the ``pd.expanding_*``,``pd.rolling_*``,``pd.ewma_*`` interface as this is polluting the top-level namespace quite a bit\r\n- [x] change the docs to use the new API\r\n\r\n```\r\nIn [4]: df = DataFrame({'A' : range(5), 'B' : pd.timedelta_range('1 day',periods=5), 'C' : 'foo'})\r\n\r\nIn [5]: df.rolling(window=2).sum()\r\nOut[5]: \r\n    A      B    C\r\n0 NaN    NaT  foo\r\n1   1 3 days  foo\r\n2   3 5 days  foo\r\n3   5 7 days  foo\r\n4   7 9 days  foo\r\n\r\nIn [6]: df.rolling(window=2)['A','C'].sum()\r\nOut[6]: \r\n    A    C\r\n0 NaN  foo\r\n1   1  foo\r\n2   3  foo\r\n3   5  foo\r\n4   7  foo\r\n\r\nIn [2]: r = df.rolling(window=3)\r\n\r\nIn [3]: r.\r\nr.A         r.C         r.corr      r.cov       r.max       r.median    r.name      r.skew      r.sum       \r\nr.B         r.apply     r.count     r.kurt      r.mean      r.min       r.quantile  r.std       r.var       \r\n```\r\n\r\ndo rolling/expanding/ewma ops\r\n```\r\nIn [1]: s = Series(range(5))\r\n\r\nIn [2]: r = s.rolling(2)\r\n\r\nI# pd.rolling_sum\r\nIn [3]: r.sum()\r\nOut[3]: \r\n0   NaN\r\n1     1\r\n2     3\r\n3     5\r\n4     7\r\ndtype: float64\r\n\r\n# nicer repr\r\nIn [4]: r\r\nOut[4]: Rolling [window->2,center->False,axis->0]\r\n\r\nIn [5]: e = s.expanding(min_periods=2)\r\n\r\n# pd.expanding_sum\r\nIn [6]: e.sum()\r\nOut[6]: \r\n0   NaN\r\n1     1\r\n2     3\r\n3     6\r\n4    10\r\ndtype: float64\r\n\r\nIn [7]: em = s.ewm(com=10)\r\n\r\n# pd.ewma\r\nIn [8]: em.mean()\r\nOut[8]: \r\n0    0.000000\r\n1    0.523810\r\n2    1.063444\r\n3    1.618832\r\n4    2.189874\r\ndtype: float64\r\n```\r\n\r\nand allow the various aggregation type of ops (similar to groupby)\r\n```\r\nIn [1]: df = DataFrame({'A' : range(5), 'B' : pd.timedelta_range('1 day',periods=5), 'C' : 'foo'})\r\n\r\nIn [2]: r = df.rolling(2,min_periods=1)\r\n\r\nIn [3]: r.agg([np.sum,np.mean])\r\nOut[3]: \r\n    A           B                    C     \r\n  sum mean    sum            mean  sum mean\r\n0   0  0.0 1 days 1 days 00:00:00  foo  foo\r\n1   1  0.5 3 days 1 days 12:00:00  foo  foo\r\n2   3  1.5 5 days 2 days 12:00:00  foo  foo\r\n3   5  2.5 7 days 3 days 12:00:00  foo  foo\r\n4   7  3.5 9 days 4 days 12:00:00  foo  foo\r\n\r\nIn [4]: r.agg({'A' : 'sum', 'B' : 'mean'})\r\nOut[4]: \r\n   A               B\r\n0  0 1 days 00:00:00\r\n1  1 1 days 12:00:00\r\n2  3 2 days 12:00:00\r\n3  5 3 days 12:00:00\r\n4  7 4 days 12:00:00\r\n```","created_at":"2015-11-14T18:12:18Z","updated_at":"2015-12-15T13:29:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e594d1ffe8f5a2081089a0dc4c35bbd4d32b6d4b","assignee":null,"milestone":{"url":"https://api.github.com/repos/pydata/pandas/milestones/36","html_url":"https://github.com/pydata/pandas/milestones/0.18.0","labels_url":"https://api.github.com/repos/pydata/pandas/milestones/36/labels","id":1214851,"number":36,"title":"0.18.0","description":"","creator":{"login":"jreback","id":953992,"avatar_url":"https://avatars.githubusercontent.com/u/953992?v=3","gravatar_id":"","url":"https://api.github.com/users/jreback","html_url":"https://github.com/jreback","followers_url":"https://api.github.com/users/jreback/followers","following_url":"https://api.github.com/users/jreback/following{/other_user}","gists_url":"https://api.github.com/users/jreback/gists{/gist_id}","starred_url":"https://api.github.com/users/jreback/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jreback/subscriptions","organizations_url":"https://api.github.com/users/jreback/orgs","repos_url":"https://api.github.com/users/jreback/repos","events_url":"https://api.github.com/users/jreback/events{/privacy}","received_events_url":"https://api.github.com/users/jreback/received_events","type":"User","site_admin":false},"open_issues":63,"closed_issues":63,"state":"open","created_at":"2015-07-19T20:18:45Z","updated_at":"2015-12-15T12:44:02Z","due_on":"2016-01-31T05:00:00Z","closed_at":null},"commits_url":"https://api.github.com/repos/pydata/pandas/pulls/11603/commits","review_comments_url":"https://api.github.com/repos/pydata/pandas/pulls/11603/comments","review_comment_url":"https://api.github.com/repos/pydata/pandas/pulls/comments{/number}","comments_url":"https://api.github.com/repos/pydata/pandas/issues/11603/comments","statuses_url":"https://api.github.com/repos/pydata/pandas/statuses/25584402f79536a962f1b989646b3229bad9815b","head":{"label":"jreback:rolling","ref":"rolling","sha":"25584402f79536a962f1b989646b3229bad9815b","user":{"login":"jreback","id":953992,"avatar_url":"https://avatars.githubusercontent.com/u/953992?v=3","gravatar_id":"","url":"https://api.github.com/users/jreback","html_url":"https://github.com/jreback","followers_url":"https://api.github.com/users/jreback/followers","following_url":"https://api.github.com/users/jreback/following{/other_user}","gists_url":"https://api.github.com/users/jreback/gists{/gist_id}","starred_url":"https://api.github.com/users/jreback/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jreback/subscriptions","organizations_url":"https://api.github.com/users/jreback/orgs","repos_url":"https://api.github.com/users/jreback/repos","events_url":"https://api.github.com/users/jreback/events{/privacy}","received_events_url":"https://api.github.com/users/jreback/received_events","type":"User","site_admin":false},"repo":{"id":2142250,"name":"pandas","full_name":"jreback/pandas","owner":{"login":"jreback","id":953992,"avatar_url":"https://avatars.githubusercontent.com/u/953992?v=3","gravatar_id":"","url":"https://api.github.com/users/jreback","html_url":"https://github.com/jreback","followers_url":"https://api.github.com/users/jreback/followers","following_url":"https://api.github.com/users/jreback/following{/other_user}","gists_url":"https://api.github.com/users/jreback/gists{/gist_id}","starred_url":"https://api.github.com/users/jreback/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jreback/subscriptions","organizations_url":"https://api.github.com/users/jreback/orgs","repos_url":"https://api.github.com/users/jreback/repos","events_url":"https://api.github.com/users/jreback/events{/privacy}","received_events_url":"https://api.github.com/users/jreback/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jreback/pandas","description":"Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more","fork":true,"url":"https://api.github.com/repos/jreback/pandas","forks_url":"https://api.github.com/repos/jreback/pandas/forks","keys_url":"https://api.github.com/repos/jreback/pandas/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jreback/pandas/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jreback/pandas/teams","hooks_url":"https://api.github.com/repos/jreback/pandas/hooks","issue_events_url":"https://api.github.com/repos/jreback/pandas/issues/events{/number}","events_url":"https://api.github.com/repos/jreback/pandas/events","assignees_url":"https://api.github.com/repos/jreback/pandas/assignees{/user}","branches_url":"https://api.github.com/repos/jreback/pandas/branches{/branch}","tags_url":"https://api.github.com/repos/jreback/pandas/tags","blobs_url":"https://api.github.com/repos/jreback/pandas/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jreback/pandas/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jreback/pandas/git/refs{/sha}","trees_url":"https://api.github.com/repos/jreback/pandas/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jreback/pandas/statuses/{sha}","languages_url":"https://api.github.com/repos/jreback/pandas/languages","stargazers_url":"https://api.github.com/repos/jreback/pandas/stargazers","contributors_url":"https://api.github.com/repos/jreback/pandas/contributors","subscribers_url":"https://api.github.com/repos/jreback/pandas/subscribers","subscription_url":"https://api.github.com/repos/jreback/pandas/subscription","commits_url":"https://api.github.com/repos/jreback/pandas/commits{/sha}","git_commits_url":"https://api.github.com/repos/jreback/pandas/git/commits{/sha}","comments_url":"https://api.github.com/repos/jreback/pandas/comments{/number}","issue_comment_url":"https://api.github.com/repos/jreback/pandas/issues/comments{/number}","contents_url":"https://api.github.com/repos/jreback/pandas/contents/{+path}","compare_url":"https://api.github.com/repos/jreback/pandas/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jreback/pandas/merges","archive_url":"https://api.github.com/repos/jreback/pandas/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jreback/pandas/downloads","issues_url":"https://api.github.com/repos/jreback/pandas/issues{/number}","pulls_url":"https://api.github.com/repos/jreback/pandas/pulls{/number}","milestones_url":"https://api.github.com/repos/jreback/pandas/milestones{/number}","notifications_url":"https://api.github.com/repos/jreback/pandas/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jreback/pandas/labels{/name}","releases_url":"https://api.github.com/repos/jreback/pandas/releases{/id}","created_at":"2011-08-02T12:17:07Z","updated_at":"2015-11-07T20:22:56Z","pushed_at":"2015-12-15T11:29:56Z","git_url":"git://github.com/jreback/pandas.git","ssh_url":"git@github.com:jreback/pandas.git","clone_url":"https://github.com/jreback/pandas.git","svn_url":"https://github.com/jreback/pandas","homepage":"http://pandas.sourceforge.net","size":71556,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":1,"forks":5,"open_issues":1,"watchers":5,"default_branch":"master"}},"base":{"label":"pydata:master","ref":"master","sha":"d0ac06af0361d0ebfcb3865b019878a20668b469","user":{"login":"pydata","id":1284191,"avatar_url":"https://avatars.githubusercontent.com/u/1284191?v=3","gravatar_id":"","url":"https://api.github.com/users/pydata","html_url":"https://github.com/pydata","followers_url":"https://api.github.com/users/pydata/followers","following_url":"https://api.github.com/users/pydata/following{/other_user}","gists_url":"https://api.github.com/users/pydata/gists{/gist_id}","starred_url":"https://api.github.com/users/pydata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pydata/subscriptions","organizations_url":"https://api.github.com/users/pydata/orgs","repos_url":"https://api.github.com/users/pydata/repos","events_url":"https://api.github.com/users/pydata/events{/privacy}","received_events_url":"https://api.github.com/users/pydata/received_events","type":"Organization","site_admin":false},"repo":{"id":858127,"name":"pandas","full_name":"pydata/pandas","owner":{"login":"pydata","id":1284191,"avatar_url":"https://avatars.githubusercontent.com/u/1284191?v=3","gravatar_id":"","url":"https://api.github.com/users/pydata","html_url":"https://github.com/pydata","followers_url":"https://api.github.com/users/pydata/followers","following_url":"https://api.github.com/users/pydata/following{/other_user}","gists_url":"https://api.github.com/users/pydata/gists{/gist_id}","starred_url":"https://api.github.com/users/pydata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pydata/subscriptions","organizations_url":"https://api.github.com/users/pydata/orgs","repos_url":"https://api.github.com/users/pydata/repos","events_url":"https://api.github.com/users/pydata/events{/privacy}","received_events_url":"https://api.github.com/users/pydata/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/pydata/pandas","description":"Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more","fork":false,"url":"https://api.github.com/repos/pydata/pandas","forks_url":"https://api.github.com/repos/pydata/pandas/forks","keys_url":"https://api.github.com/repos/pydata/pandas/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pydata/pandas/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pydata/pandas/teams","hooks_url":"https://api.github.com/repos/pydata/pandas/hooks","issue_events_url":"https://api.github.com/repos/pydata/pandas/issues/events{/number}","events_url":"https://api.github.com/repos/pydata/pandas/events","assignees_url":"https://api.github.com/repos/pydata/pandas/assignees{/user}","branches_url":"https://api.github.com/repos/pydata/pandas/branches{/branch}","tags_url":"https://api.github.com/repos/pydata/pandas/tags","blobs_url":"https://api.github.com/repos/pydata/pandas/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pydata/pandas/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pydata/pandas/git/refs{/sha}","trees_url":"https://api.github.com/repos/pydata/pandas/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pydata/pandas/statuses/{sha}","languages_url":"https://api.github.com/repos/pydata/pandas/languages","stargazers_url":"https://api.github.com/repos/pydata/pandas/stargazers","contributors_url":"https://api.github.com/repos/pydata/pandas/contributors","subscribers_url":"https://api.github.com/repos/pydata/pandas/subscribers","subscription_url":"https://api.github.com/repos/pydata/pandas/subscription","commits_url":"https://api.github.com/repos/pydata/pandas/commits{/sha}","git_commits_url":"https://api.github.com/repos/pydata/pandas/git/commits{/sha}","comments_url":"https://api.github.com/repos/pydata/pandas/comments{/number}","issue_comment_url":"https://api.github.com/repos/pydata/pandas/issues/comments{/number}","contents_url":"https://api.github.com/repos/pydata/pandas/contents/{+path}","compare_url":"https://api.github.com/repos/pydata/pandas/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pydata/pandas/merges","archive_url":"https://api.github.com/repos/pydata/pandas/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pydata/pandas/downloads","issues_url":"https://api.github.com/repos/pydata/pandas/issues{/number}","pulls_url":"https://api.github.com/repos/pydata/pandas/pulls{/number}","milestones_url":"https://api.github.com/repos/pydata/pandas/milestones{/number}","notifications_url":"https://api.github.com/repos/pydata/pandas/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pydata/pandas/labels{/name}","releases_url":"https://api.github.com/repos/pydata/pandas/releases{/id}","created_at":"2010-08-24T01:37:33Z","updated_at":"2015-12-15T12:21:53Z","pushed_at":"2015-12-15T12:58:44Z","git_url":"git://github.com/pydata/pandas.git","ssh_url":"git@github.com:pydata/pandas.git","clone_url":"https://github.com/pydata/pandas.git","svn_url":"https://github.com/pydata/pandas","homepage":"http://pandas.pydata.org","size":129325,"stargazers_count":5441,"watchers_count":5441,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2148,"mirror_url":null,"open_issues_count":1551,"forks":2148,"open_issues":1551,"watchers":5441,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/pydata/pandas/pulls/11603"},"html":{"href":"https://github.com/pydata/pandas/pull/11603"},"issue":{"href":"https://api.github.com/repos/pydata/pandas/issues/11603"},"comments":{"href":"https://api.github.com/repos/pydata/pandas/issues/11603/comments"},"review_comments":{"href":"https://api.github.com/repos/pydata/pandas/pulls/11603/comments"},"review_comment":{"href":"https://api.github.com/repos/pydata/pandas/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/pydata/pandas/pulls/11603/commits"},"statuses":{"href":"https://api.github.com/repos/pydata/pandas/statuses/25584402f79536a962f1b989646b3229bad9815b"}}}}