diff --git a/doc/source/whatsnew/v1.5.0.rst b/doc/source/whatsnew/v1.5.0.rst index 8bb924f4003a2..aaf166dab99c3 100644 --- a/doc/source/whatsnew/v1.5.0.rst +++ b/doc/source/whatsnew/v1.5.0.rst @@ -205,6 +205,7 @@ Performance improvements - Performance improvement in :meth:`.GroupBy.transform` for some user-defined DataFrame -> Series functions (:issue:`45387`) - Performance improvement in :meth:`DataFrame.duplicated` when subset consists of only one column (:issue:`45236`) - Performance improvement in :meth:`.GroupBy.transform` when broadcasting values for user-defined functions (:issue:`45708`) +- Performance improvement in :meth:`.GroupBy.transform` for user-defined functions when only a single group exists (:issue:`44977`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 949f369849323..80c704698938e 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -1208,6 +1208,11 @@ def _choose_path(self, fast_path: Callable, slow_path: Callable, group: DataFram path = slow_path res = slow_path(group) + if self.ngroups == 1: + # no need to evaluate multiple paths when only + # a single group exists + return path, res + # if we make it here, test if we can use the fast path try: res_fast = fast_path(group) diff --git a/pandas/tests/groupby/transform/test_transform.py b/pandas/tests/groupby/transform/test_transform.py index 1dde70ebb4b1b..6e9b8c35b3698 100644 --- a/pandas/tests/groupby/transform/test_transform.py +++ b/pandas/tests/groupby/transform/test_transform.py @@ -480,7 +480,7 @@ def test_transform_coercion(): # 14457 # when we are transforming be sure to not coerce # via assignment - df = DataFrame({"A": ["a", "a"], "B": [0, 1]}) + df = DataFrame({"A": ["a", "a", "b", "b"], "B": [0, 1, 3, 4]}) g = df.groupby("A") expected = g.transform(np.mean)