diff --git a/doc/source/whatsnew/v3.0.0.rst b/doc/source/whatsnew/v3.0.0.rst index bad06329c4bfa..acf6970e2e1ca 100644 --- a/doc/source/whatsnew/v3.0.0.rst +++ b/doc/source/whatsnew/v3.0.0.rst @@ -56,6 +56,7 @@ Other enhancements - :meth:`DataFrame.cummin`, :meth:`DataFrame.cummax`, :meth:`DataFrame.cumprod` and :meth:`DataFrame.cumsum` methods now have a ``numeric_only`` parameter (:issue:`53072`) - :meth:`DataFrame.ewm` now allows ``adjust=False`` when ``times`` is provided (:issue:`54328`) - :meth:`DataFrame.fillna` and :meth:`Series.fillna` can now accept ``value=None``; for non-object dtype the corresponding NA value will be used (:issue:`57723`) +- :meth:`DataFrame.groupby` now accepts no fields for ``groupby`` by in :meth:`DataFrame.groupby` (:issue:`61160`) - :meth:`DataFrame.pivot_table` and :func:`pivot_table` now allow the passing of keyword arguments to ``aggfunc`` through ``**kwargs`` (:issue:`57884`) - :meth:`DataFrame.to_json` now encodes ``Decimal`` as strings instead of floats (:issue:`60698`) - :meth:`Series.cummin` and :meth:`Series.cummax` now supports :class:`CategoricalDtype` (:issue:`52335`) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8f65277f660f7..66d1fc7815ac1 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9153,8 +9153,8 @@ def groupby( ) -> DataFrameGroupBy: from pandas.core.groupby.generic import DataFrameGroupBy - if level is None and by is None: - raise TypeError("You have to supply one of 'by' and 'level'") + if level is None and (by is None or by == []): + by = Series(0, index=self.index) return DataFrameGroupBy( obj=self, diff --git a/pandas/core/series.py b/pandas/core/series.py index 258e0100a8558..21a35784c0b4d 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1973,8 +1973,8 @@ def groupby( ) -> SeriesGroupBy: from pandas.core.groupby.generic import SeriesGroupBy - if level is None and by is None: - raise TypeError("You have to supply one of 'by' and 'level'") + if level is None and (by is None or by == []): + by = Series(0, index=self.index) if not as_index: raise TypeError("as_index=False only valid with DataFrame") diff --git a/pandas/tests/groupby/test_grouping.py b/pandas/tests/groupby/test_grouping.py index 53e9c53efebf7..d9a80a1855152 100644 --- a/pandas/tests/groupby/test_grouping.py +++ b/pandas/tests/groupby/test_grouping.py @@ -695,17 +695,45 @@ def test_groupby_level_with_nas(self, sort): expected = Series([6.0, 18.0], index=[0.0, 1.0]) tm.assert_series_equal(result, expected) + def test_groupby_without_by(self): + # GH 61160 + df = DataFrame({"A": [1, 2, 3, 4], "B": [10, 20, 30, 40]}) + + # Test basic aggregation with no fields + result = df.groupby().sum() + expected = df.sum().to_frame().T + tm.assert_frame_equal(result, expected) + + # Test with multiple aggregations + result = df.groupby().agg(["sum", "mean"]) + expected = df.agg(["sum", "mean"]) + tm.assert_frame_equal(result, expected) + + # Test Series.groupby() without any fields + s = Series([1, 2, 3, 4]) + result = s.groupby().sum() + expected = Series([10]) # Sum of the values + tm.assert_series_equal(result, expected) + + # Test with conditional logic - should work with None/empty list + groupby_fields = None + result = df.groupby(groupby_fields).sum() + expected = df.sum().to_frame().T + tm.assert_frame_equal(result, expected) + + result = df.groupby([]).sum() + tm.assert_frame_equal(result, expected) + def test_groupby_args(self, multiindex_dataframe_random_data): # PR8618 and issue 8015 frame = multiindex_dataframe_random_data - msg = "You have to supply one of 'by' and 'level'" - with pytest.raises(TypeError, match=msg): - frame.groupby() + result = frame.groupby().sum() + expected = frame.sum().to_frame().T + tm.assert_frame_equal(result, expected) - msg = "You have to supply one of 'by' and 'level'" - with pytest.raises(TypeError, match=msg): - frame.groupby(by=None, level=None) + result = frame.groupby(by=None, level=None).sum() + tm.assert_frame_equal(result, expected) @pytest.mark.parametrize( "sort,labels",