
polars 升级至 0.20.7 后,`group_by([...])` 传入列表会导致 `map_groups` 报错“cannot call `map_groups` when grouping by an expression”;根本原因是新版本未自动解包单元素列表,正确写法应为 `group_by('product number')`(无方括号),并推荐优先使用更高效、更安全的 `over()` 窗口函数替代 `map_groups`。
在 Polars 0.20.7 中,group_by() 方法已支持灵活的参数形式(如 group_by('col')、group_by('col1', 'col2')),以与其他 API(如 select、with_columns)保持一致。但这一改动导致一个兼容性陷阱:若仍沿用旧写法 group_by(['Product Number'])(即传入列表),map_groups 内部逻辑会误判 self.by 为含非字符串类型的表达式(因 ['Product Number'] 是 list,而非纯 str),从而触发类型检查失败:
# ❌ 错误写法(触发 TypeError)
df.group_by(['Product Number']).map_groups(...)
# ✅ 正确写法:直接传字符串,不加方括号
df.group_by('Product Number').map_groups(...)修正后的 map_groups 示例代码如下:
import polars as pl
df1 = (
df1
.group_by('Product Number')
.map_groups(lambda g: (
g.with_columns(
pl.col('New Date')
.fill_null(strategy='backward')
.alias('New Date1')
)
))
)⚠️ 但请注意:map_groups 并非此场景的最佳选择。它会将每组数据实例化为独立的 DataFrame,带来显著的内存与性能开销,且丧失 Polars 的惰性计算和向量化优势。
✅ 推荐替代方案:使用 over() 窗口函数
对分组内列执行填充操作,应优先采用 over() —— 它原生支持分组上下文、零拷贝、完全向量化,且语法简洁:
df1 = df1.with_columns(
pl.col('New Date')
.fill_null(strategy='backward')
.over('Product Number')
.alias('New Date1')
)该写法等价于“按 'Product Number' 分组,在每组内对 'New Date' 列进行反向填充”,语义清晰、性能优异,且完全规避 map_groups 的限制与风险。
? 额外最佳实践提醒:
- 始终使用 pl.col('col_name') 替代 df['col_name'] 在 with_columns/select 等上下文中,后者属于 pandas 风格,在 Polars 中易引发作用域错误或意外行为;
- 若需更复杂的组内逻辑(如自定义聚合+变换),可结合 agg() 与结构化返回,或升级至 0.20.8+(已合并 PR #14099,彻底解除 map_groups 对列表输入的限制);
- 所有窗口操作(包括 over)均支持链式调用,可无缝集成进现有 pipeline。
综上,面对 map_groups 兼容性报错,首选修复是去除 group_by 的方括号;而面向长期可维护性与性能,应主动迁移至 over() —— 这既是 Polars 的惯用范式,也是现代 DataFrame 计算的更优路径。










