Skip to content

Commit f235902

Browse files
committed
ENH: Fixed DF.apply for functions returning a dict (closes #8735)
1 parent c3a4de3 commit f235902

File tree

4 files changed

+27
-3
lines changed

4 files changed

+27
-3
lines changed

doc/source/whatsnew/v0.17.0.txt

+2
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ Other enhancements
218218

219219
- Support pickling of ``Period`` objects (:issue:`10439`)
220220

221+
- ``DataFrame.apply`` will return a Series of dicts if the passed function returns a dict and ``reduce=True`` (:issue:`8735`).
222+
221223
.. _whatsnew_0170.api:
222224

223225
.. _whatsnew_0170.api_breaking:

pandas/core/frame.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -3922,10 +3922,13 @@ def _apply_standard(self, func, axis, ignore_failures=False, reduce=True):
39223922
if reduce:
39233923

39243924
try:
3925-
39263925
# the is the fast-path
39273926
values = self.values
3928-
dummy = Series(NA, index=self._get_axis(axis),
3927+
# Create a dummy Series from an empty array
3928+
# Unlike filling with NA, this works for any dtype
3929+
index = self._get_axis(axis)
3930+
empty_arr = np.empty(len(index), dtype=values.dtype)
3931+
dummy = Series(empty_arr, index=self._get_axis(axis),
39293932
dtype=values.dtype)
39303933

39313934
labels = self._get_agg_axis(axis)

pandas/src/reduce.pyx

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ cdef class Reducer:
133133
else:
134134
res = self.f(chunk)
135135

136-
if hasattr(res,'values'):
136+
if hasattr(res,'values') and isinstance(res.values, np.ndarray):
137137
res = res.values
138138
if i == 0:
139139
result = _get_result_array(res,

pandas/tests/test_frame.py

+19
Original file line numberDiff line numberDiff line change
@@ -11255,6 +11255,25 @@ def test_apply_multi_index(self):
1125511255
res = s.apply(lambda x: Series({'min': min(x), 'max': max(x)}), 1)
1125611256
tm.assertIsInstance(res.index, MultiIndex)
1125711257

11258+
def test_apply_dict(self):
11259+
11260+
# GH 8735
11261+
A = DataFrame([['foo', 'bar'], ['spam', 'eggs']])
11262+
A_dicts = pd.Series([dict([(0, 'foo'), (1, 'spam')]),
11263+
dict([(0, 'bar'), (1, 'eggs')])])
11264+
B = DataFrame([[0, 1], [2, 3]])
11265+
B_dicts = pd.Series([dict([(0, 0), (1, 2)]), dict([(0, 1), (1, 3)])])
11266+
fn = lambda x: x.to_dict()
11267+
11268+
for df, dicts in [(A, A_dicts), (B, B_dicts)]:
11269+
reduce_true = df.apply(fn, reduce=True)
11270+
reduce_false = df.apply(fn, reduce=False)
11271+
reduce_none = df.apply(fn, reduce=None)
11272+
11273+
assert_series_equal(reduce_true, dicts)
11274+
assert_frame_equal(reduce_false, df)
11275+
assert_series_equal(reduce_none, dicts)
11276+
1125811277
def test_applymap(self):
1125911278
applied = self.frame.applymap(lambda x: x * 2)
1126011279
assert_frame_equal(applied, self.frame * 2)

0 commit comments

Comments
 (0)