From f4605a472fe825d11acec9af95bc6afe4ccd7f96 Mon Sep 17 00:00:00 2001 From: discort Date: Mon, 13 Aug 2018 10:27:07 +0300 Subject: [PATCH 1/2] Added quantile method to Resampler --- doc/source/api.rst | 1 + doc/source/whatsnew/v0.24.0.txt | 1 + pandas/core/resample.py | 12 ++++++++++++ pandas/tests/test_resample.py | 9 ++++++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/source/api.rst b/doc/source/api.rst index 551b3eff10fa0..77d37ec2a7b2e 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -2352,6 +2352,7 @@ Computations / Descriptive Stats Resampler.std Resampler.sum Resampler.var + Resampler.quantile Style ----- diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 9e1d2487b00fe..6aaaefd300cb0 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -183,6 +183,7 @@ Other Enhancements - :class:`Series` and :class:`DataFrame` now support :class:`Iterable` in constructor (:issue:`2193`) - :class:`DatetimeIndex` gained :attr:`DatetimeIndex.timetz` attribute. Returns local time with timezone information. (:issue:`21358`) - :class:`Resampler` now is iterable like :class:`GroupBy` (:issue:`15314`). +- Added :meth:`Resampler.quantile` (:issue:`15023`). .. _whatsnew_0240.api_breaking: diff --git a/pandas/core/resample.py b/pandas/core/resample.py index b9194443c3033..b92068de7d41f 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -766,6 +766,18 @@ def size(self): result = pd.Series([], index=result.index, dtype='int64') return result + def quantile(self, q=0.5, **kwargs): + """ + Return value at the given quantile. + + Parameters + ---------- + q : float or array-like, default 0.5 (50% quantile) + + .. versionadded:: 0.24.0 + """ + return self._downsample('quantile', q=q, **kwargs) + # downsample methods for method in ['sum', 'prod']: diff --git a/pandas/tests/test_resample.py b/pandas/tests/test_resample.py index 48b37e5da62ae..48b00f3d875b9 100644 --- a/pandas/tests/test_resample.py +++ b/pandas/tests/test_resample.py @@ -41,7 +41,7 @@ # The various methods we support downsample_methods = ['min', 'max', 'first', 'last', 'sum', 'mean', 'sem', - 'median', 'prod', 'var', 'ohlc'] + 'median', 'prod', 'var', 'ohlc', 'quantile'] upsample_methods = ['count', 'size'] series_methods = ['nunique'] resample_methods = downsample_methods + upsample_methods + series_methods @@ -2176,6 +2176,13 @@ def test_resample_datetime_values(self): res = df['timestamp'].resample('2D').first() tm.assert_series_equal(res, exp) + def test_resample_quantile(self): + # GH 15023 + s = pd.Series(range(20), index=date_range('2016-01-01', periods=20)) + result = s.resample('W').quantile(0.75) + expected = s.resample('W').agg(lambda x: x.quantile(0.75)) + tm.assert_series_equal(result, expected) + class TestPeriodIndex(Base): _index_factory = lambda x: period_range From 92b5b2d7164ade76ff425831d763ce8b1c11cece Mon Sep 17 00:00:00 2001 From: discort Date: Tue, 14 Aug 2018 13:12:54 +0300 Subject: [PATCH 2/2] addressed Jeff's comments --- doc/source/whatsnew/v0.24.0.txt | 2 +- pandas/core/groupby/groupby.py | 7 ++++++- pandas/core/resample.py | 11 +++++++++-- pandas/tests/test_resample.py | 16 +++++++++------- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 6aaaefd300cb0..a3d4a95a7d01a 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -183,7 +183,7 @@ Other Enhancements - :class:`Series` and :class:`DataFrame` now support :class:`Iterable` in constructor (:issue:`2193`) - :class:`DatetimeIndex` gained :attr:`DatetimeIndex.timetz` attribute. Returns local time with timezone information. (:issue:`21358`) - :class:`Resampler` now is iterable like :class:`GroupBy` (:issue:`15314`). -- Added :meth:`Resampler.quantile` (:issue:`15023`). +- :ref:`Series.resample` and :ref:`DataFrame.resample` have gained the :meth:`Resampler.quantile` (:issue:`15023`). .. _whatsnew_0240.api_breaking: diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 3f84fa0f0670e..61dadd833be35 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -1168,7 +1168,12 @@ def var(self, ddof=1, *args, **kwargs): """ nv.validate_groupby_func('var', args, kwargs) if ddof == 1: - return self._cython_agg_general('var', **kwargs) + try: + return self._cython_agg_general('var', **kwargs) + except Exception: + f = lambda x: x.var(ddof=ddof, **kwargs) + with _group_selection_context(self): + return self._python_agg_general(f) else: f = lambda x: x.var(ddof=ddof, **kwargs) with _group_selection_context(self): diff --git a/pandas/core/resample.py b/pandas/core/resample.py index b92068de7d41f..3d749848afdad 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -770,11 +770,17 @@ def quantile(self, q=0.5, **kwargs): """ Return value at the given quantile. + .. versionadded:: 0.24.0 + Parameters ---------- q : float or array-like, default 0.5 (50% quantile) - .. versionadded:: 0.24.0 + See Also + -------- + Series.quantile + DataFrame.quantile + DataFrameGroupBy.quantile """ return self._downsample('quantile', q=q, **kwargs) @@ -1072,7 +1078,8 @@ def _downsample(self, how, **kwargs): if is_subperiod(ax.freq, self.freq): # Downsampling - return self._groupby_and_aggregate(how, grouper=self.grouper) + return self._groupby_and_aggregate(how, grouper=self.grouper, + **kwargs) elif is_superperiod(ax.freq, self.freq): if how == 'ohlc': # GH #13083 diff --git a/pandas/tests/test_resample.py b/pandas/tests/test_resample.py index 48b00f3d875b9..b80c041a7e69f 100644 --- a/pandas/tests/test_resample.py +++ b/pandas/tests/test_resample.py @@ -782,6 +782,15 @@ def test_resampler_is_iterable(self): assert rk == gk assert_series_equal(rv, gv) + def test_resample_quantile(self): + # GH 15023 + s = self.create_series() + q = 0.75 + freq = 'H' + result = s.resample(freq).quantile(q) + expected = s.resample(freq).agg(lambda x: x.quantile(q)) + tm.assert_series_equal(result, expected) + class TestDatetimeIndex(Base): _index_factory = lambda x: date_range @@ -2176,13 +2185,6 @@ def test_resample_datetime_values(self): res = df['timestamp'].resample('2D').first() tm.assert_series_equal(res, exp) - def test_resample_quantile(self): - # GH 15023 - s = pd.Series(range(20), index=date_range('2016-01-01', periods=20)) - result = s.resample('W').quantile(0.75) - expected = s.resample('W').agg(lambda x: x.quantile(0.75)) - tm.assert_series_equal(result, expected) - class TestPeriodIndex(Base): _index_factory = lambda x: period_range