{"action":"created","comment":{"url":"https://api.github.com/repos/pydata/pandas/pulls/comments/46068710","id":46068710,"diff_hunk":"@@ -0,0 +1,1339 @@\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 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+:func:`pandas.Series.%(name)s`\n+:func:`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+        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\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\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\n+    Method for down- or re-sampling\"\"\")","path":"pandas/core/window.py","position":490,"original_position":490,"commit_id":"f86747136e3bab8aa0c3f261df795a6339f06c8a","original_commit_id":"526f37160ee97dfc5244a6b4a57a4fb3228a2764","user":{"login":"shoyer","id":1217238,"avatar_url":"https://avatars.githubusercontent.com/u/1217238?v=3","gravatar_id":"","url":"https://api.github.com/users/shoyer","html_url":"https://github.com/shoyer","followers_url":"https://api.github.com/users/shoyer/followers","following_url":"https://api.github.com/users/shoyer/following{/other_user}","gists_url":"https://api.github.com/users/shoyer/gists{/gist_id}","starred_url":"https://api.github.com/users/shoyer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shoyer/subscriptions","organizations_url":"https://api.github.com/users/shoyer/orgs","repos_url":"https://api.github.com/users/shoyer/repos","events_url":"https://api.github.com/users/shoyer/events{/privacy}","received_events_url":"https://api.github.com/users/shoyer/received_events","type":"User","site_admin":false},"body":"+1 on deprecating the freq argument. It complicates the API unnecessarily.\n\nOn Fri, Nov 27, 2015 at 6:19 AM, Joris Van den Bossche\n<notifications@github.com> wrote:\n\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\n>> +    Method for down- or re-sampling\"\"\")\n> yes, the `freq`/`how` is a bit problematic with the new api .. \n> My suggestion would be to just completely leave it out (you can always do resample yourself, and if you want it to apply it on several functions with different 'how's, then you will just have to do it in multiple steps ..\n> ---\n> Reply to this email directly or view it on GitHub:\n> https://github.com/pydata/pandas/pull/11603/files#r46050243","created_at":"2015-11-27T20:10:55Z","updated_at":"2015-11-27T20:10:55Z","html_url":"https://github.com/pydata/pandas/pull/11603#discussion_r46068710","pull_request_url":"https://api.github.com/repos/pydata/pandas/pulls/11603","_links":{"self":{"href":"https://api.github.com/repos/pydata/pandas/pulls/comments/46068710"},"html":{"href":"https://github.com/pydata/pandas/pull/11603#discussion_r46068710"},"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-11-27T20:10:55Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c6aea0cd2ea94b2a267995251054c27847e15a53","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":30,"closed_issues":10,"state":"open","created_at":"2015-07-19T20:18:45Z","updated_at":"2015-11-27T13:40:22Z","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/f86747136e3bab8aa0c3f261df795a6339f06c8a","head":{"label":"jreback:rolling","ref":"rolling","sha":"f86747136e3bab8aa0c3f261df795a6339f06c8a","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-11-27T14:12:57Z","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":70238,"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":"e8382665d12dcf270f587cf76cd0e6d5a1dac184","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-11-27T17:43:38Z","pushed_at":"2015-11-27T20:09:28Z","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":128144,"stargazers_count":5343,"watchers_count":5343,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":2106,"mirror_url":null,"open_issues_count":1519,"forks":2106,"open_issues":1519,"watchers":5343,"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/f86747136e3bab8aa0c3f261df795a6339f06c8a"}}}}