diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index b83f317814ad9..00fe5a062ea81 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -181,7 +181,7 @@ Plotting Groupby/resample/rolling ^^^^^^^^^^^^^^^^^^^^^^^^ -- +- Bug in :meth:`DataFrameGroupBy.idxmin`, :meth:`SeriesGroupBy.idxmin`, :meth:`DataFrameGroupBy.idxmax`, :meth:`SeriesGroupBy.idxmax` return wrong dtype when used on empty DataFrameGroupBy or SeriesGroupBy (:issue:`51423`) - Reshaping diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 67188d91bca70..58ae2205f38d2 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -1084,12 +1084,12 @@ def nsmallest( @doc(Series.idxmin.__doc__) def idxmin(self, axis: Axis = 0, skipna: bool = True) -> Series: result = self._op_via_apply("idxmin", axis=axis, skipna=skipna) - return result + return result.astype(self.obj.index.dtype) if result.empty else result @doc(Series.idxmax.__doc__) def idxmax(self, axis: Axis = 0, skipna: bool = True) -> Series: result = self._op_via_apply("idxmax", axis=axis, skipna=skipna) - return result + return result.astype(self.obj.index.dtype) if result.empty else result @doc(Series.corr.__doc__) def corr( @@ -2018,7 +2018,7 @@ def func(df): result = self._python_apply_general( func, self._obj_with_exclusions, not_indexed_same=True ) - return result + return result.astype(self.obj.index.dtype) if result.empty else result def idxmin( self, @@ -2104,7 +2104,7 @@ def func(df): result = self._python_apply_general( func, self._obj_with_exclusions, not_indexed_same=True ) - return result + return result.astype(self.obj.index.dtype) if result.empty else result boxplot = boxplot_frame_groupby diff --git a/pandas/tests/groupby/test_groupby.py b/pandas/tests/groupby/test_groupby.py index d969ce4a2bb71..540cb7ba6645d 100644 --- a/pandas/tests/groupby/test_groupby.py +++ b/pandas/tests/groupby/test_groupby.py @@ -1984,6 +1984,8 @@ def get_categorical_invalid_expected(): result = get_result() expected = df.set_index(keys)[columns] + if op in ["idxmax", "idxmin"]: + expected = expected.astype(df.index.dtype) if override_dtype is not None: expected = expected.astype(override_dtype) if len(keys) == 1: