Skip to content

Commit 9f25c79

Browse files
committed
BUG: infer better return type in DataFrame.apply with empty frame, GH #389
1 parent 500c76b commit 9f25c79

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

RELEASE.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Where to get it
2222
* Binary installers on PyPI: http://pypi.python.org/pypi/pandas
2323
* Documentation: http://pandas.sourceforge.net
2424

25-
pandas 0.5.1
25+
pandas 0.6.0
2626
============
2727

2828
**Release date:** Not yet released

pandas/core/frame.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -2204,7 +2204,8 @@ def apply(self, func, axis=0, broadcast=False, raw=False):
22042204
22052205
Notes
22062206
-----
2207-
Functions should not alter the index of the Series passed to them
2207+
Function passed should not have side effects. If the result is a Series,
2208+
it should have the same index
22082209
22092210
Returns
22102211
-------
@@ -2219,6 +2220,14 @@ def apply(self, func, axis=0, broadcast=False, raw=False):
22192220
columns=self.columns, copy=False)
22202221
else:
22212222
if not broadcast:
2223+
if not all(self.shape):
2224+
is_reduction = not isinstance(func(_EMPTY_SERIES),
2225+
np.ndarray)
2226+
if is_reduction:
2227+
return Series(np.nan, index=self._get_agg_axis(axis))
2228+
else:
2229+
return self.copy()
2230+
22222231
if raw and not self._is_mixed_type:
22232232
return self._apply_raw(func, axis)
22242233
else:
@@ -2246,7 +2255,7 @@ def _apply_standard(self, func, axis, ignore_failures=False):
22462255
dummy = Series(np.nan, index=self._get_axis(axis),
22472256
dtype=values.dtype)
22482257
result = lib.reduce(values, func, axis=axis, dummy=dummy)
2249-
return Series(result, index=self._get_agg_axis(axis))
2258+
return Series(result, index=agg_axis)
22502259
except Exception:
22512260
pass
22522261

@@ -3254,6 +3263,9 @@ def combineMult(self, other):
32543263
return self.mul(other, fill_value=1.)
32553264

32563265

3266+
_EMPTY_SERIES = Series([])
3267+
3268+
32573269
class _DataFrameFormatter(object):
32583270
"""
32593271
Render a DataFrame

pandas/tests/test_frame.py

+30
Original file line numberDiff line numberDiff line change
@@ -2684,6 +2684,36 @@ def test_apply_mixed_dtype_corner(self):
26842684
expected = Series(np.nan, index=[])
26852685
assert_series_equal(result, expected)
26862686

2687+
def test_apply_empty_infer_type(self):
2688+
no_cols = DataFrame(index=['a', 'b', 'c'])
2689+
no_index = DataFrame(columns=['a', 'b', 'c'])
2690+
2691+
def _check(df, f):
2692+
test_res = f(np.array([], dtype='f8'))
2693+
is_reduction = not isinstance(test_res, np.ndarray)
2694+
2695+
def _checkit(axis=0, raw=False):
2696+
res = df.apply(f, axis=axis, raw=raw)
2697+
if is_reduction:
2698+
agg_axis = df._get_agg_axis(axis)
2699+
self.assert_(isinstance(res, Series))
2700+
self.assert_(res.index is agg_axis)
2701+
else:
2702+
self.assert_(isinstance(res, DataFrame))
2703+
2704+
_checkit()
2705+
_checkit(axis=1)
2706+
_checkit(raw=True)
2707+
_checkit(axis=0, raw=True)
2708+
2709+
_check(no_cols, lambda x: x)
2710+
_check(no_cols, lambda x: x.mean())
2711+
_check(no_index, lambda x: x)
2712+
_check(no_index, lambda x: x.mean())
2713+
2714+
result = no_cols.apply(lambda x: x.mean(), broadcast=True)
2715+
self.assert_(isinstance(result, DataFrame))
2716+
26872717
def test_applymap(self):
26882718
applied = self.frame.applymap(lambda x: x * 2)
26892719
assert_frame_equal(applied, self.frame * 2)

setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@
128128
]
129129

130130
MAJOR = 0
131-
MINOR = 5
132-
MICRO = 1
131+
MINOR = 6
132+
MICRO = 0
133133
ISRELEASED = False
134134
VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
135135
QUALIFIER = ''

0 commit comments

Comments
 (0)