diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 17cdb7538dad2..9c4de5c888299 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -619,6 +619,7 @@ Numeric - Bug in :class:`DataFrame` allowing arithmetic operations with list of array-likes with undefined results. Behavior changed to raising ``ValueError`` (:issue:`36702`) - Bug in :meth:`DataFrame.std` with ``timedelta64`` dtype and ``skipna=False`` (:issue:`37392`) - Bug in :meth:`DataFrame.min` and :meth:`DataFrame.max` with ``datetime64`` dtype and ``skipna=False`` (:issue:`36907`) +- Bug in :meth:`DataFrame.idxmax` and :meth:`DataFrame.idxmin` with mixed dtypes incorrectly raising ``TypeError`` (:issue:`38195`) Conversion ^^^^^^^^^^ diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 9cc9c9ef200cd..5f149f10b05d3 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9001,7 +9001,11 @@ def idxmin(self, axis=0, skipna=True) -> Series: dtype: object """ axis = self._get_axis_number(axis) - indices = nanops.nanargmin(self.values, axis=axis, skipna=skipna) + + res = self._reduce( + nanops.nanargmin, "argmin", axis=axis, skipna=skipna, numeric_only=False + ) + indices = res._values # indices will always be np.ndarray since axis is not None and # values is a 2d array for DataFrame @@ -9074,7 +9078,11 @@ def idxmax(self, axis=0, skipna=True) -> Series: dtype: object """ axis = self._get_axis_number(axis) - indices = nanops.nanargmax(self.values, axis=axis, skipna=skipna) + + res = self._reduce( + nanops.nanargmax, "argmax", axis=axis, skipna=skipna, numeric_only=False + ) + indices = res._values # indices will always be np.ndarray since axis is not None and # values is a 2d array for DataFrame diff --git a/pandas/tests/frame/test_reductions.py b/pandas/tests/frame/test_reductions.py index 299f00e818105..8cf1e17dfd1d0 100644 --- a/pandas/tests/frame/test_reductions.py +++ b/pandas/tests/frame/test_reductions.py @@ -969,6 +969,20 @@ def test_idxmax(self, float_frame, int_frame): with pytest.raises(ValueError, match=msg): frame.idxmax(axis=2) + def test_idxmax_mixed_dtype(self): + # don't cast to object, which would raise in nanops + dti = pd.date_range("2016-01-01", periods=3) + + df = DataFrame({1: [0, 2, 1], 2: range(3)[::-1], 3: dti}) + + result = df.idxmax() + expected = Series([1, 0, 2], index=[1, 2, 3]) + tm.assert_series_equal(result, expected) + + result = df.idxmin() + expected = Series([0, 2, 0], index=[1, 2, 3]) + tm.assert_series_equal(result, expected) + # ---------------------------------------------------------------------- # Logical reductions