{"record":{"id":"03925b03ad776ec1","repo":"pola-rs/polars","slug":"cannot-call-map-groups-when-grouping-by-named-ex","errorCode":null,"errorMessage":"cannot call `map_groups` when grouping by named expressions","messagePattern":"cannot call `map_groups` when grouping by named expressions","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/dataframe/group_by.py","lineNumber":450,"sourceCode":"        ╞═════╪═══════╪══════════╡\n        │ 1   ┆ green ┆ triangle │\n        │ 2   ┆ green ┆ square   │\n        │ 4   ┆ red   ┆ square   │\n        │ 3   ┆ red   ┆ triangle │\n        └─────┴───────┴──────────┘\n\n        It is better to implement this with an expression:\n\n        >>> df.filter(\n        ...     pl.int_range(pl.len()).shuffle().over(\"color\") < 2\n        ... )  # doctest: +IGNORE_RESULT\n        \"\"\"\n        if self.predicates:\n            msg = \"cannot call `map_groups` when filtering groups with `having`\"\n            raise TypeError(msg)\n        if self.named_by:\n            msg = \"cannot call `map_groups` when grouping by named expressions\"\n            raise TypeError(msg)\n        by = list(_parse_inputs_as_iterable(self.by))\n        if not all(isinstance(c, str) for c in by):\n            msg = \"cannot call `map_groups` when grouping by an expression\"\n            raise TypeError(msg)\n\n        return self.df.__class__._from_pydf(\n            self.df._df.group_by_map_groups(by, function, self.maintain_order)\n        )\n\n    def head(self, n: int = 5) -> DataFrame:\n        \"\"\"\n        Get the first `n` rows of each group.\n\n        Parameters\n        ----------\n        n\n            Number of rows to return.\n","sourceCodeStart":432,"sourceCodeEnd":468,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/dataframe/group_by.py#L432-L468","documentation":"GroupBy.map_groups hands each group's sub-DataFrame to a Python function via the Rust group_by_map_groups path, which identifies groups by plain column names only. Named expressions (keyword arguments like df.group_by(grp=pl.col('a') + 1)) create derived/aliased keys that this path cannot resolve back to columns, so polars raises TypeError when the GroupBy object carries any named_by entries.","triggerScenarios":"df.group_by(grp=pl.col('a') % 10).map_groups(fn); any group_by call using keyword=Expr arguments and then chaining .map_groups(...); refactors that renamed grouping keys via kwargs for readability.","commonSituations":"Using named-expression syntax (fine for .agg) on pipelines that end in map_groups; deriving grouping keys on the fly (alias in the group_by) instead of precomputing a column; mixed style within a codebase.","solutions":["Group by plain column names only: df.group_by('a').map_groups(fn)","Precompute derived keys as a column first: df.with_columns((pl.col('a') % 10).alias('grp')).group_by('grp').map_groups(fn)","Rename or alias the key after map_groups if a different output name is needed"],"exampleFix":"# before\nout = df.group_by(grp=pl.col('a') % 10).map_groups(process_group)\n\n# after\nout = (\n    df.with_columns((pl.col('a') % 10).alias('grp'))\n      .group_by('grp')\n      .map_groups(process_group)\n)","handlingStrategy":"validation","validationCode":"def safe_map_groups(gb, fn):\n    if getattr(gb, 'named_by', None):\n        raise TypeError('map_groups requires plain column-name keys; precompute derived keys as columns')\n    return gb.map_groups(fn)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reserve kwargs (named expressions) for .agg pipelines; use positional column names for map_groups","Materialize derived keys with with_columns(...).alias(...) before grouping","Alias/rename grouping keys after map_groups rather than at group_by time"],"tags":["polars","group-by","map-groups","named-expressions","typeerror","api-combination"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}