diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index dfbbb456f50b6..7a1ccb3fa9ac3 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -194,6 +194,7 @@ Other enhancements - Added :meth:`Rolling.sem()` and :meth:`Expanding.sem()` to compute the standard error of mean (:issue:`26476`). - :meth:`Rolling.var()` and :meth:`Rolling.std()` use Kahan summation and Welfords Method to avoid numerical issues (:issue:`37051`) - :meth:`DataFrame.plot` now recognizes ``xlabel`` and ``ylabel`` arguments for plots of type ``scatter`` and ``hexbin`` (:issue:`37001`) +- :class:`DataFrame` now supports ``divmod`` operation (:issue:`37165`) .. _whatsnew_120.api_breaking.python: diff --git a/pandas/core/frame.py b/pandas/core/frame.py index aca626805a0e3..a017ecf53c6ad 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -5957,6 +5957,18 @@ def _construct_result(self, result) -> DataFrame: out.index = self.index return out + def __divmod__(self, other) -> Tuple[DataFrame, DataFrame]: + # Naive implementation, room for optimization + div = self // other + mod = self - div * other + return div, mod + + def __rdivmod__(self, other) -> Tuple[DataFrame, DataFrame]: + # Naive implementation, room for optimization + div = other // self + mod = other - div * self + return div, mod + # ---------------------------------------------------------------------- # Combination-Related diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 3e979aed0551f..90a3ed6d75393 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -1900,10 +1900,13 @@ def test_td64arr_mod_tdscalar(self, box_with_array, three_days): result = tdarr % three_days tm.assert_equal(result, expected) - if box_with_array is pd.DataFrame: - pytest.xfail("DataFrame does not have __divmod__ or __rdivmod__") + warn = None + if box_with_array is pd.DataFrame and isinstance(three_days, pd.DateOffset): + warn = PerformanceWarning + + with tm.assert_produces_warning(warn): + result = divmod(tdarr, three_days) - result = divmod(tdarr, three_days) tm.assert_equal(result[1], expected) tm.assert_equal(result[0], tdarr // three_days) @@ -1921,9 +1924,6 @@ def test_td64arr_mod_int(self, box_with_array): with pytest.raises(TypeError, match=msg): 2 % tdarr - if box_with_array is pd.DataFrame: - pytest.xfail("DataFrame does not have __divmod__ or __rdivmod__") - result = divmod(tdarr, 2) tm.assert_equal(result[1], expected) tm.assert_equal(result[0], tdarr // 2) @@ -1939,9 +1939,6 @@ def test_td64arr_rmod_tdscalar(self, box_with_array, three_days): result = three_days % tdarr tm.assert_equal(result, expected) - if box_with_array is pd.DataFrame: - pytest.xfail("DataFrame does not have __divmod__ or __rdivmod__") - result = divmod(three_days, tdarr) tm.assert_equal(result[1], expected) tm.assert_equal(result[0], three_days // tdarr)