Skip to content

Commit

Permalink
BUG: addtl fix for compat summary of groupby/resample with dicts
Browse files Browse the repository at this point in the history
closes #9052  closes #12332

Author: Jeff Reback <jeff@reback.net>

Closes #12329 from jreback/groupby_compat and squashes the following commits:

0d8561e [Jeff Reback] BUG: resampling with a how could trigger asfreq instead
66c23aa [Jeff Reback] BUG: addtl fix for compat summary of groupby/resample with dicts
  • Loading branch information
jreback committed Feb 15, 2016
1 parent b358876 commit cac5f8b
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 23 deletions.
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.18.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ other anchored offsets like ``MonthBegin`` and ``YearBegin``.
Resample API
^^^^^^^^^^^^

Like the change in the window functions API :ref:`above <whatsnew_0180.enhancements.moments>`, ``.resample(...)`` is changing to have a more groupby-like API. (:issue:`11732`, :issue:`12702`, :issue:`12202`).
Like the change in the window functions API :ref:`above <whatsnew_0180.enhancements.moments>`, ``.resample(...)`` is changing to have a more groupby-like API. (:issue:`11732`, :issue:`12702`, :issue:`12202`, :issue:`12332`).

.. ipython:: python

Expand Down
23 changes: 14 additions & 9 deletions pandas/core/groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -2526,7 +2526,8 @@ def aggregate(self, func_or_funcs, *args, **kwargs):
return getattr(self, func_or_funcs)(*args, **kwargs)

if hasattr(func_or_funcs, '__iter__'):
ret = self._aggregate_multiple_funcs(func_or_funcs, _level)
ret = self._aggregate_multiple_funcs(func_or_funcs,
(_level or 0) + 1)
else:
cyfunc = self._is_cython_func(func_or_funcs)
if cyfunc and not args and not kwargs:
Expand All @@ -2546,6 +2547,18 @@ def aggregate(self, func_or_funcs, *args, **kwargs):
if not self.as_index: # pragma: no cover
print('Warning, ignoring as_index=True')

# _level handled at higher
if not _level and isinstance(ret, dict):
from pandas import concat

# our result is a Series-like
if len(ret) == 1:
ret = concat([r for r in ret.values()],
axis=1)

# our result is a DataFrame like
else:
ret = concat(ret, axis=1)
return ret

agg = aggregate
Expand All @@ -2571,14 +2584,6 @@ def _aggregate_multiple_funcs(self, arg, _level):
columns.append(com._get_callable_name(f))
arg = lzip(columns, arg)

# for a ndim=1, disallow a nested dict for an aggregator as
# this is a mis-specification of the aggregations, via a
# specificiation error
# e.g. g['A'].agg({'A': ..., 'B': ...})
if self.name in columns and len(columns) > 1:
raise SpecificationError('invalid aggregation names specified '
'for selected objects')

results = {}
for name, func in arg:
obj = self
Expand Down
7 changes: 7 additions & 0 deletions pandas/tests/test_groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,13 @@ def f():
'ra', 'std'), ('rb', 'mean'), ('rb', 'std')])
assert_frame_equal(result, expected, check_like=True)

# same name as the original column
# GH9052
expected = g['D'].agg({'result1': np.sum, 'result2': np.mean})
expected = expected.rename(columns={'result1': 'D'})
result = g['D'].agg({'D': np.sum, 'result2': np.mean})
assert_frame_equal(result, expected, check_like=True)

def test_multi_iter(self):
s = Series(np.arange(6))
k1 = np.array(['a', 'a', 'a', 'b', 'b', 'b'])
Expand Down
2 changes: 1 addition & 1 deletion pandas/tseries/resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ def _downsample(self, how, **kwargs):
# do we have a regular frequency
if ax.freq is not None or ax.inferred_freq is not None:

if len(self.grouper.binlabels) > len(ax):
if len(self.grouper.binlabels) > len(ax) and how is None:

# let's do an asfreq
return self.asfreq()
Expand Down
44 changes: 32 additions & 12 deletions pandas/tseries/tests/test_resample.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,25 +419,32 @@ def test_agg_misc(self):
assert_frame_equal(result, expected, check_like=True)

# series like aggs
expected = pd.concat([t['A'].sum(),
t['A'].std()],
axis=1)
expected.columns = ['sum', 'std']

for t in [r, g]:
result = r['A'].agg({'A': ['sum', 'std']})
result = t['A'].agg({'A': ['sum', 'std']})
expected = pd.concat([t['A'].sum(),
t['A'].std()],
axis=1)
expected.columns = ['sum', 'std']

assert_frame_equal(result, expected, check_like=True)

expected = pd.concat([t['A'].agg(['sum', 'std']),
t['A'].agg(['mean', 'std'])],
axis=1)
expected.columns = pd.MultiIndex.from_tuples([('A', 'sum'),
('A', 'std'),
('B', 'mean'),
('B', 'std')])
result = t['A'].agg({'A': ['sum', 'std'], 'B': ['mean', 'std']})
assert_frame_equal(result, expected, check_like=True)

# errors
# invalid names in the agg specification
for t in [r, g]:

# invalid names in the agg specification
def f():
r['A'].agg({'A': ['sum', 'std'], 'B': ['mean', 'std']})
self.assertRaises(SpecificationError, f)

def f():
r[['A']].agg({'A': ['sum', 'std'], 'B': ['mean', 'std']})
r[['A']].agg({'A': ['sum', 'std'],
'B': ['mean', 'std']})
self.assertRaises(SpecificationError, f)

def test_agg_nested_dicts(self):
Expand Down Expand Up @@ -918,6 +925,19 @@ def test_resample_ohlc(self):
self.assertEqual(xs['low'], s[:5].min())
self.assertEqual(xs['close'], s[4])

def test_resample_ohlc_result(self):

# GH 12332
index = pd.date_range('1-1-2000', '2-15-2000', freq='h')
index = index.union(pd.date_range('4-15-2000', '5-15-2000', freq='h'))
s = Series(range(len(index)), index=index)

a = s.loc[:'4-15-2000'].resample('30T').ohlc()
self.assertIsInstance(a, DataFrame)

b = s.loc[:'4-14-2000'].resample('30T').ohlc()
self.assertIsInstance(b, DataFrame)

def test_resample_ohlc_dataframe(self):
df = (
pd.DataFrame({
Expand Down

0 comments on commit cac5f8b

Please sign in to comment.