Skip to content

Commit 674fb96

Browse files
bobhaffnerjreback
authored andcommitted
BUG fixes tuple agg issue 18079 (pandas-dev#18354)
1 parent 982ad07 commit 674fb96

File tree

3 files changed

+39
-5
lines changed

3 files changed

+39
-5
lines changed

doc/source/whatsnew/v0.22.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ Plotting
169169
Groupby/Resample/Rolling
170170
^^^^^^^^^^^^^^^^^^^^^^^^
171171

172-
-
172+
- Bug when grouping by a single column and aggregating with a class like ``list`` or ``tuple`` (:issue:`18079`)
173173
-
174174
-
175175

pandas/core/groupby.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -2299,8 +2299,7 @@ def _aggregate_series_pure_python(self, obj, func):
22992299
for label, group in splitter:
23002300
res = func(group)
23012301
if result is None:
2302-
if (isinstance(res, (Series, Index, np.ndarray)) or
2303-
isinstance(res, list)):
2302+
if (isinstance(res, (Series, Index, np.ndarray))):
23042303
raise ValueError('Function does not reduce')
23052304
result = np.empty(ngroups, dtype='O')
23062305

@@ -3022,7 +3021,9 @@ def aggregate(self, func_or_funcs, *args, **kwargs):
30223021
if isinstance(func_or_funcs, compat.string_types):
30233022
return getattr(self, func_or_funcs)(*args, **kwargs)
30243023

3025-
if hasattr(func_or_funcs, '__iter__'):
3024+
if isinstance(func_or_funcs, collections.Iterable):
3025+
# Catch instances of lists / tuples
3026+
# but not the class list / tuple itself.
30263027
ret = self._aggregate_multiple_funcs(func_or_funcs,
30273028
(_level or 0) + 1)
30283029
else:

pandas/tests/groupby/test_aggregate.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ def test_agg_consistency(self):
637637
def P1(a):
638638
try:
639639
return np.percentile(a.dropna(), q=1)
640-
except:
640+
except Exception:
641641
return np.nan
642642

643643
import datetime as dt
@@ -892,3 +892,36 @@ def test_sum_uint64_overflow(self):
892892
expected.index.name = 0
893893
result = df.groupby(0).sum()
894894
tm.assert_frame_equal(result, expected)
895+
896+
@pytest.mark.parametrize("structure, expected", [
897+
(tuple, pd.DataFrame({'C': {(1, 1): (1, 1, 1), (3, 4): (3, 4, 4)}})),
898+
(list, pd.DataFrame({'C': {(1, 1): [1, 1, 1], (3, 4): [3, 4, 4]}})),
899+
(lambda x: tuple(x), pd.DataFrame({'C': {(1, 1): (1, 1, 1),
900+
(3, 4): (3, 4, 4)}})),
901+
(lambda x: list(x), pd.DataFrame({'C': {(1, 1): [1, 1, 1],
902+
(3, 4): [3, 4, 4]}}))
903+
])
904+
def test_agg_structs_dataframe(self, structure, expected):
905+
df = pd.DataFrame({'A': [1, 1, 1, 3, 3, 3],
906+
'B': [1, 1, 1, 4, 4, 4], 'C': [1, 1, 1, 3, 4, 4]})
907+
908+
result = df.groupby(['A', 'B']).aggregate(structure)
909+
expected.index.names = ['A', 'B']
910+
assert_frame_equal(result, expected)
911+
912+
@pytest.mark.parametrize("structure, expected", [
913+
(tuple, pd.Series([(1, 1, 1), (3, 4, 4)], index=[1, 3], name='C')),
914+
(list, pd.Series([[1, 1, 1], [3, 4, 4]], index=[1, 3], name='C')),
915+
(lambda x: tuple(x), pd.Series([(1, 1, 1), (3, 4, 4)],
916+
index=[1, 3], name='C')),
917+
(lambda x: list(x), pd.Series([[1, 1, 1], [3, 4, 4]],
918+
index=[1, 3], name='C'))
919+
])
920+
def test_agg_structs_series(self, structure, expected):
921+
# Issue #18079
922+
df = pd.DataFrame({'A': [1, 1, 1, 3, 3, 3],
923+
'B': [1, 1, 1, 4, 4, 4], 'C': [1, 1, 1, 3, 4, 4]})
924+
925+
result = df.groupby('A')['C'].aggregate(structure)
926+
expected.index.name = 'A'
927+
assert_series_equal(result, expected)

0 commit comments

Comments
 (0)