diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 9840e4e94d28c..9aa374f92a9aa 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -206,8 +206,8 @@ Groupby/resample/rolling Reshaping ^^^^^^^^^ +- Bug in :meth:`DataFrame.apply` that caused incorrect output with empty :class:`DataFrame` (:issue:`28202`, :issue:`21959`) - Bug in :meth:`DataFrame.stack` not handling non-unique indexes correctly when creating MultiIndex (:issue: `28301`) -- Sparse ^^^^^^ diff --git a/pandas/core/apply.py b/pandas/core/apply.py index e6766a33a613b..61d093d19e4be 100644 --- a/pandas/core/apply.py +++ b/pandas/core/apply.py @@ -204,17 +204,20 @@ def apply_empty_result(self): from pandas import Series if not should_reduce: - - EMPTY_SERIES = Series([]) try: - r = self.f(EMPTY_SERIES, *self.args, **self.kwds) + r = self.f(Series([])) except Exception: pass else: should_reduce = not isinstance(r, Series) if should_reduce: - return self.obj._constructor_sliced(np.nan, index=self.agg_axis) + if len(self.agg_axis): + r = self.f(Series([])) + else: + r = np.nan + + return self.obj._constructor_sliced(r, index=self.agg_axis) else: return self.obj.copy() diff --git a/pandas/tests/frame/test_apply.py b/pandas/tests/frame/test_apply.py index 92912ff9ec093..0328232213588 100644 --- a/pandas/tests/frame/test_apply.py +++ b/pandas/tests/frame/test_apply.py @@ -116,6 +116,27 @@ def test_apply_with_reduce_empty(self): # Ensure that x.append hasn't been called assert x == [] + @pytest.mark.parametrize("func", ["sum", "prod", "any", "all"]) + def test_apply_funcs_over_empty(self, func): + # GH 28213 + df = DataFrame(columns=["a", "b", "c"]) + + result = df.apply(getattr(np, func)) + expected = getattr(df, func)() + assert_series_equal(result, expected) + + def test_nunique_empty(self): + # GH 28213 + df = DataFrame(columns=["a", "b", "c"]) + + result = df.nunique() + expected = Series(0, index=df.columns) + assert_series_equal(result, expected) + + result = df.T.nunique() + expected = Series([], index=pd.Index([])) + assert_series_equal(result, expected) + def test_apply_deprecate_reduce(self): empty_frame = DataFrame()