diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index e244794664b34..a03746deebf68 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -898,6 +898,7 @@ Groupby/resample/rolling - Bug in :meth:`DataFrame.ewm` when passed ``times`` with non-nanosecond ``datetime64`` or :class:`DatetimeTZDtype` dtype (:issue:`56262`) - Bug in :meth:`DataFrame.groupby` and :meth:`Series.groupby` where grouping by a combination of ``Decimal`` and NA values would fail when ``sort=True`` (:issue:`54847`) - Bug in :meth:`DataFrame.groupby` for DataFrame subclasses when selecting a subset of columns to apply the function to (:issue:`56761`) +- Bug in :meth:`DataFrame.resample` changing index type to :class:`MultiIndex` when the dataframe is empty and using an upsample method (:issue:`55572`) - Bug in :meth:`DataFrame.resample` not respecting ``closed`` and ``label`` arguments for :class:`~pandas.tseries.offsets.BusinessDay` (:issue:`55282`) - Bug in :meth:`DataFrame.resample` when resampling on a :class:`ArrowDtype` of ``pyarrow.timestamp`` or ``pyarrow.duration`` type (:issue:`55989`) - Bug in :meth:`DataFrame.resample` where bin edges were not correct for :class:`~pandas.tseries.offsets.BusinessDay` (:issue:`55281`) diff --git a/pandas/core/resample.py b/pandas/core/resample.py index 48a5f85e1c388..a87615d8c1784 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -494,22 +494,12 @@ def _wrap_result(self, result): """ Potentially wrap any results. """ - # GH 47705 - obj = self.obj - if ( - isinstance(result, ABCDataFrame) - and len(result) == 0 - and not isinstance(result.index, PeriodIndex) - ): - result = result.set_index( - _asfreq_compat(obj.index[:0], freq=self.freq), append=True - ) - if isinstance(result, ABCSeries) and self._selection is not None: result.name = self._selection if isinstance(result, ABCSeries) and result.empty: # When index is all NaT, result is empty but index is not + obj = self.obj result.index = _asfreq_compat(obj.index[:0], freq=self.freq) result.name = getattr(obj, "name", None) @@ -1675,6 +1665,17 @@ def func(x): return x.apply(f, *args, **kwargs) result = _apply(self._groupby, func, include_groups=self.include_groups) + + # GH 47705 + if ( + isinstance(result, ABCDataFrame) + and len(result) == 0 + and not isinstance(result.index, PeriodIndex) + ): + result = result.set_index( + _asfreq_compat(self.obj.index[:0], freq=self.freq), append=True + ) + return self._wrap_result(result) _upsample = _apply diff --git a/pandas/tests/resample/test_base.py b/pandas/tests/resample/test_base.py index ab75dd7469b73..7a6c7eba1193d 100644 --- a/pandas/tests/resample/test_base.py +++ b/pandas/tests/resample/test_base.py @@ -337,6 +337,44 @@ def test_resample_size_empty_dataframe(freq, index): tm.assert_series_equal(result, expected) +@pytest.mark.parametrize( + "index", [DatetimeIndex([]), TimedeltaIndex([]), PeriodIndex([], freq="D")] +) +@pytest.mark.parametrize("freq", ["ME", "D", "h"]) +@pytest.mark.parametrize( + "method", ["ffill", "bfill", "nearest", "asfreq", "interpolate"] +) +def test_resample_upsample_empty_dataframe(index, freq, method): + # GH#55572 + empty_frame_dti = DataFrame(index=index) + + if freq == "ME" and isinstance(empty_frame_dti.index, TimedeltaIndex): + msg = ( + "Resampling on a TimedeltaIndex requires fixed-duration `freq`, " + "e.g. '24h' or '3D', not " + ) + with pytest.raises(ValueError, match=msg): + empty_frame_dti.resample(freq) + return + elif freq == "ME" and isinstance(empty_frame_dti.index, PeriodIndex): + # index is PeriodIndex, so convert to corresponding Period freq + freq = "M" + + msg = "Resampling with a PeriodIndex" + warn = None + if isinstance(empty_frame_dti.index, PeriodIndex): + warn = FutureWarning + + with tm.assert_produces_warning(warn, match=msg): + rs = empty_frame_dti.resample(freq) + result = getattr(rs, method)() + + expected_index = _asfreq_compat(empty_frame_dti.index, freq) + expected = DataFrame([], index=expected_index) + + tm.assert_frame_equal(result, expected) + + @pytest.mark.parametrize( "index", [