diff --git a/pandas/core/base.py b/pandas/core/base.py index 1c74c977e39bc..e070005c56d7a 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -602,9 +602,9 @@ def _aggregate_multiple_funcs(self, arg, _level, _axis): if not len(results): raise ValueError("no results") - if all(np.ndim(x) > 0 for x in results): + try: return concat(results, keys=keys, axis=1, sort=False) - else: + except TypeError: # we are concatting non-NDFrame objects, # e.g. a list of scalars diff --git a/pandas/tests/frame/test_apply.py b/pandas/tests/frame/test_apply.py index fea50b3b7f75d..ad53fcf29c57d 100644 --- a/pandas/tests/frame/test_apply.py +++ b/pandas/tests/frame/test_apply.py @@ -1259,6 +1259,23 @@ def test_non_callable_aggregates(self): assert result == expected + def test_agg_listlike_result(self): + # GH-29587 user defined function returning list-likes + df = DataFrame( + {"A": [2, 2, 3], "B": [1.5, np.nan, 1.5], "C": ["foo", None, "bar"]} + ) + + def func(group_col): + return list(group_col.dropna().unique()) + + result = df.agg(func) + expected = pd.Series([[2, 3], [1.5], ["foo", "bar"]], index=["A", "B", "C"]) + tm.assert_series_equal(result, expected) + + result = df.agg([func]) + expected = expected.to_frame("func").T + tm.assert_frame_equal(result, expected) + @pytest.mark.parametrize( "df, func, expected", chain(