Skip to content

Commit d4810f0

Browse files
committed
ENH: return DataFrame if Series.apply function returns Series. close #2316
1 parent 3bf6a46 commit d4810f0

File tree

3 files changed

+19
-16
lines changed

3 files changed

+19
-16
lines changed

RELEASE.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pandas 0.10.0
4242
this can rename the columns. To fix legacy code, put ``header=None`` when
4343
passing ``names``
4444
- DataFrame selection using a boolean frame now preserves input shape
45+
- If function passed to Series.apply yields a Series, result will be a
46+
DataFrame (#2316)
4547

4648
**Improvements to existing features**
4749

pandas/core/series.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,9 +2119,9 @@ def map_f(values, f):
21192119

21202120
def apply(self, func, convert_dtype=True, args=(), **kwds):
21212121
"""
2122-
Invoke function on values of Series. Can be ufunc, a Python function
2123-
that applies to the entire Series, or a Python function that only
2124-
works on single values
2122+
Invoke function on values of Series. Can be ufunc (a NumPy function
2123+
that applies to the entire Series) or a Python function that only works
2124+
on single values
21252125
21262126
Parameters
21272127
----------
@@ -2141,22 +2141,21 @@ def apply(self, func, convert_dtype=True, args=(), **kwds):
21412141
21422142
Returns
21432143
-------
2144-
y : Series
2144+
y : Series or DataFrame if func returns a Series
21452145
"""
21462146
if kwds or args and not isinstance(func, np.ufunc):
21472147
f = lambda x: func(x, *args, **kwds)
21482148
else:
21492149
f = func
21502150

2151-
try:
2152-
result = f(self)
2153-
if isinstance(result, np.ndarray):
2154-
result = Series(result, index=self.index, name=self.name)
2155-
else:
2156-
raise ValueError('Must yield array')
2157-
return result
2158-
except Exception:
2159-
mapped = lib.map_infer(self.values, f, convert=convert_dtype)
2151+
if isinstance(f, np.ufunc):
2152+
return f(self)
2153+
2154+
mapped = lib.map_infer(self.values, f, convert=convert_dtype)
2155+
if isinstance(mapped[0], Series):
2156+
from pandas.core.frame import DataFrame
2157+
return DataFrame(mapped.tolist(), index=self.index)
2158+
else:
21602159
return Series(mapped, index=self.index, name=self.name)
21612160

21622161
def align(self, other, join='outer', level=None, copy=True,

pandas/tests/test_series.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,9 +2513,11 @@ def test_apply(self):
25132513
import math
25142514
assert_series_equal(self.ts.apply(math.exp), np.exp(self.ts))
25152515

2516-
# does not return Series
2517-
result = self.ts.apply(lambda x: x.values * 2)
2518-
assert_series_equal(result, self.ts * 2)
2516+
# how to handle Series result, #2316
2517+
result = self.ts.apply(lambda x: Series([x, x ** 2],
2518+
index=['x', 'x^2']))
2519+
expected = DataFrame({'x': self.ts, 'x^2': self.ts **2})
2520+
tm.assert_frame_equal(result, expected)
25192521

25202522
def test_apply_same_length_inference_bug(self):
25212523
s = Series([1, 2])

0 commit comments

Comments
 (0)