news 2026/9/12 11:28:29

Polars 的 pivot 为什么不能在 Lazy 查询中直接执行?如何用 on_columns 声明结果 schema?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Polars 的 pivot 为什么不能在 Lazy 查询中直接执行?如何用 on_columns 声明结果 schema?

Polars 的 pivot 为什么不能在 Lazy 查询中直接执行?如何用 on_columns 声明结果 schema?

【免费下载链接】polarsExtremely fast Query Engine for DataFrames, written in Rust项目地址: https://gitcode.com/GitHub_Trending/po/polars

如果你用 Polars 的LazyFrame组织查询,想把“长表”改成“宽表”(例如把某列的取值变成输出表的列名),会撞上一个限制:pivot 的输出 schema 取决于数据本身,不先跑查询就确定不了结果有哪些列。官方用户指南 Pivots 与 Schema 给出了两条可执行路径:先.collect()物化出DataFrame再做 pivot,或者用on_columns参数提前静态声明结果 schema。本文按这两条路径展开操作与验证方式,适用于 Python Polars API。

为什么 pivot 无法直接放进 Lazy 查询

原因在两篇文档中都有说明:

  • LazyFrame 要求查询在collect之前就静态知道每一步计算的 schema:“A PolarsLazyFramealways need to know the schema of a computation statically (before collecting the query). As a pivot's output schema depends on the data, and it is therefore impossible to determine the schema without running the query.”(pivot.md)
  • 换个角度:lazy 查询优化器必须能在查询计划的每一步推断 schema,而 pivot 的新列名来自某一列的数据值,无法预先知道:“In a.pivotthe new column names come from data in one of the columns. As these column names cannot be known in advance a.pivotis not available in the lazy API.”(schemas.md)

这一点也体现在两个pivot方法的签名差异上:DataFrame.pivoton_columns默认为None(eager 模式可以直接从数据推断列),而LazyFrame.pivoton_columns是必传参数(DataFrame.pivot、LazyFrame.pivot)。

路径一:先 .collect() 物化,再对 DataFrame 做 pivot

这是 schemas.md 给出的通用处理模式,适用于无法提前枚举on 列取值的情况。步骤是:

  1. 流水线在 pivot 之前保持 lazy 模式;
  2. .collect()执行到这一步,物化为DataFrame
  3. DataFrame上执行.pivot
  4. .lazy()转回LazyFrame继续 lazy 模式;
  5. 最后.collect()得到结果DataFrame

文档中的完整示例(对应 schema.py):

import polars as pl lazy_eager_query = ( pl.LazyFrame( { "id": ["a", "b", "c"], "month": ["jan", "feb", "mar"], "values": [0, 1, 2], } ) .with_columns((2 * pl.col("values")).alias("double_values")) .collect() .pivot(index="id", on="month", values="double_values", aggregate_function="first") .lazy() .filter(pl.col("mar").is_null()) .collect() ) print(lazy_eager_query)

注意 pivot 之后接.filter(pl.col("mar").is_null()):此时mar已经是 pivot 生成的一列,后续 lazy 操作可以正常引用它。代价是官方文档明示的 “sacrificing lazy evaluation benefits”——pivot 之前的部分被提前执行,无法整体延迟优化。

路径二:用 on_columns 静态声明结果 schema

如果 on 列的取值集合是有限且已知的(固定的月份名、类别名等),就可以在 lazy 查询里直接写 pivot,条件是把on_columns声明出来。这是 pivot.md 给出的第二个选项:“you may specify theon_columnsparameter upfront to declare the resulting schema statically.”

先用 pivot.py 中的数据构造数据集:

import polars as pl df = pl.DataFrame( { "foo": ["A", "A", "B", "B", "C"], "N": [1, 2, 2, 4, 2], "bar": ["k", "l", "m", "n", "o"], } )

对比 eager 写法(不需要on_columns,列名从数据推断):

out = df.pivot("bar", index="foo", values="N", aggregate_function="first") print(out)

同样的 pivot 放进 lazy 查询时,必须传入on_columns(对应 pivot.py 的lazy-on-columns段):

q = df.lazy().pivot( index="foo", on="bar", on_columns=["k", "l", "m", "n", "o"], values="N", aggregate_function="first", ) out = q.collect() print(out)

on_columnsLazyFrame.pivot的 docstring 中定义为 “What value combinations will be considered for the output table”(输出表考虑哪些值组合),类型为Sequence[Any] | pl.Series | pl.DataFrame。也就是说:你声明哪些值,结果的 schema 就包含哪些列,查询在collect之前就能确定输出列。

验证结果 schema

DataFrameLazyFrame都有.collect_schema方法可以查看列名与数据类型(schemas.md)。对用on_columns声明过的查询,这一点正是验证手段——collect之前就能拿到静态输出 schema:

print(q.collect_schema())

如果collect_schema()返回的列名与index列加上on_columns各值一致,说明 schema 已按声明静态确定;之后再q.collect()取结果。

collect的输出以 LazyFrame.pivot docstring 中的文档示例为准(下表中mathsphysics两列名即来自on_columns,因为只有一个values列,列名直接用on_columns的值):

>>> df = pl.DataFrame( ... { ... "name": ["Cady", "Cady", "Karen", "Karen"], ... "subject": ["maths", "physics", "maths", "physics"], ... "test_1": [98, 99, 61, 58], ... "test_2": [100, 100, 60, 60], ... } ... ) >>> df.lazy().pivot( ... "subject", ... on_columns=["maths", "physics"], ... index="name", ... values="test_1", ... ).collect() shape: (2, 3) ┌───────┬───────┬─────────┐ │ name ┆ maths ┆ physics │ │ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ i64 │ ╞═══════╪═══════╪═════════╡ │ Cady ┆ 98 ┆ 99 │ │ Karen ┆ 61 ┆ 58 │ └───────┴───────┴─────────┘

参数与限制

  • aggregate_function:可选'min''max''first''last''sum''mean''median''len''item',也可以传入通过pl.element()构造的表达式做自定义聚合(该表达式只能访问 pivot 生成的values列)。传None表示不做聚合,此时若同一组内出现多个值会报错(LazyFrame.pivot)。用户指南 pivot.md 列出的常用聚合为 first、last、sum、min、max、mean、median、len。
  • 多个 values 列时的列名:生成的列名由 values 列名与on_columns的值组合而成(例如test_1_maths),分隔符由separator控制(默认"_");column_naming可取'auto'(默认,多 values 列时组合命名)或'combine'(始终组合),docstring 明确标注该功能为unstable,可能随时变更。
  • 引擎支持LazyFrame.pivot的 docstring 标注.. engine-support:: in-memory, partially-streaming,即该操作的引擎支持状态为 in-memory、partially-streaming,引用这一限制前以该方法文档为准。
  • 两条路径的选择依据:on 列取值无法提前枚举时用路径一(collect 后 pivot);取值集合已知时可用路径二,保持查询整体 lazy。由于结果 schema 完全由声明的on_columns决定,输出表只考虑其中列出的值组合,数据取值集合变化时需要同步更新声明。

相关文档:Pivots、Schema、pivot.py 示例、schema.py 示例。

【免费下载链接】polarsExtremely fast Query Engine for DataFrames, written in Rust项目地址: https://gitcode.com/GitHub_Trending/po/polars

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 11:26:08

LangChain与HomeAssistant构建AI智能家居决策系统

1. 项目概述:AI智能体如何重塑智能家居体验作为一名长期深耕AI与物联网交叉领域的技术从业者,我见证了智能家居从简单的远程控制到如今AI驱动的主动服务演进全过程。最近完成的这个项目,通过LangChain框架构建的AI智能体中枢,将Ho…

作者头像 李华
网站建设 2026/9/12 11:25:03

Django开发流浪动物领养系统:技术实现与公益价值

1. 项目概述:流浪动物领养系统的技术实现与价值去年参与某动物保护组织的IT系统升级时,我亲眼目睹了纸质档案管理的种种不便——领养申请堆积如山、动物信息更新滞后、志愿者排班混乱。这正是我决定用Django开发流浪动物领养系统的初衷。这个毕业设计级别…

作者头像 李华