diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index c1d9b2744b27e..988d0db8543e8 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -1105,6 +1105,7 @@ Period - Bug in adding a :class:`Period` object to an array of :class:`DateOffset` objects incorrectly raising ``TypeError`` (:issue:`50162`) - Bug in :class:`Period` where passing a string with finer resolution than nanosecond would result in a ``KeyError`` instead of dropping the extra precision (:issue:`50417`) - Bug in parsing strings representing Week-periods e.g. "2017-01-23/2017-01-29" as minute-frequency instead of week-frequency (:issue:`50803`) +- Bug in :meth:`GroupBy.sum`, :meth:`GroupBy.cumsum`, :meth:`GroupBy.prod`, :meth:`GroupBy.cumprod` with :class:`PeriodDtype` failing to raise ``TypeError`` (:issue:`51040`) - Plotting diff --git a/pandas/core/groupby/ops.py b/pandas/core/groupby/ops.py index f88236b2464c1..ced3190206f37 100644 --- a/pandas/core/groupby/ops.py +++ b/pandas/core/groupby/ops.py @@ -55,6 +55,7 @@ is_float_dtype, is_integer_dtype, is_numeric_dtype, + is_period_dtype, is_sparse, is_timedelta64_dtype, needs_i8_conversion, @@ -249,16 +250,17 @@ def _disallow_invalid_ops(self, dtype: DtypeObj, is_numeric: bool = False): raise NotImplementedError(f"{dtype} dtype not supported") elif is_sparse(dtype): - # categoricals are only 1d, so we - # are not setup for dim transforming raise NotImplementedError(f"{dtype} dtype not supported") elif is_datetime64_any_dtype(dtype): - # TODO: same for period_dtype? no for these methods with Period - # we raise NotImplemented if this is an invalid operation - # entirely, e.g. adding datetimes + # Adding/multiplying datetimes is not valid if how in ["sum", "prod", "cumsum", "cumprod"]: raise TypeError(f"datetime64 type does not support {how} operations") + elif is_period_dtype(dtype): + # Adding/multiplying Periods is not valid + if how in ["sum", "prod", "cumsum", "cumprod"]: + raise TypeError(f"Period type does not support {how} operations") elif is_timedelta64_dtype(dtype): + # timedeltas we can add but not multiply if how in ["prod", "cumprod"]: raise TypeError(f"timedelta64 type does not support {how} operations") diff --git a/pandas/tests/extension/base/groupby.py b/pandas/tests/extension/base/groupby.py index 200a494997116..9b8f3a43fbe64 100644 --- a/pandas/tests/extension/base/groupby.py +++ b/pandas/tests/extension/base/groupby.py @@ -4,7 +4,6 @@ is_bool_dtype, is_numeric_dtype, is_object_dtype, - is_period_dtype, is_string_dtype, ) @@ -135,7 +134,6 @@ def test_in_numeric_groupby(self, data_for_grouping): or is_bool_dtype(dtype) or dtype.name == "decimal" or is_string_dtype(dtype) - or is_period_dtype(dtype) or is_object_dtype(dtype) or dtype.kind == "m" # in particular duration[*][pyarrow] ): diff --git a/pandas/tests/groupby/test_groupby.py b/pandas/tests/groupby/test_groupby.py index a1c1930c2e11b..e9b18836e003c 100644 --- a/pandas/tests/groupby/test_groupby.py +++ b/pandas/tests/groupby/test_groupby.py @@ -2867,3 +2867,34 @@ def test_groupby_method_drop_na(method): else: expected = DataFrame({"A": ["a", "b", "c"], "B": [0, 2, 4]}, index=[0, 2, 4]) tm.assert_frame_equal(result, expected) + + +def test_groupby_reduce_period(): + # GH#51040 + pi = pd.period_range("2016-01-01", periods=100, freq="D") + grps = list(range(10)) * 10 + ser = pi.to_series() + gb = ser.groupby(grps) + + with pytest.raises(TypeError, match="Period type does not support sum operations"): + gb.sum() + with pytest.raises( + TypeError, match="Period type does not support cumsum operations" + ): + gb.cumsum() + with pytest.raises(TypeError, match="Period type does not support prod operations"): + gb.prod() + with pytest.raises( + TypeError, match="Period type does not support cumprod operations" + ): + gb.cumprod() + + res = gb.max() + expected = ser[-10:] + expected.index = Index(range(10), dtype=np.int_) + tm.assert_series_equal(res, expected) + + res = gb.min() + expected = ser[:10] + expected.index = Index(range(10), dtype=np.int_) + tm.assert_series_equal(res, expected)