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

发布时间:2026/9/12 11:28:38
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 pivots 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.pivot的on_columns默认为Noneeager 模式可以直接从数据推断列而LazyFrame.pivot的on_columns是必传参数DataFrame.pivot、LazyFrame.pivot。路径一先 .collect() 物化再对 DataFrame 做 pivot这是 schemas.md 给出的通用处理模式适用于无法提前枚举on 列取值的情况。步骤是流水线在 pivot 之前保持 lazy 模式用.collect()执行到这一步物化为DataFrame在DataFrame上执行.pivot用.lazy()转回LazyFrame继续 lazy 模式最后.collect()得到结果DataFrame。文档中的完整示例对应 schema.pyimport 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(indexid, onmonth, valuesdouble_values, aggregate_functionfirst) .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, indexfoo, valuesN, aggregate_functionfirst) print(out)同样的 pivot 放进 lazy 查询时必须传入on_columns对应 pivot.py 的lazy-on-columns段q df.lazy().pivot( indexfoo, onbar, on_columns[k, l, m, n, o], valuesN, aggregate_functionfirst, ) out q.collect() print(out)on_columns在LazyFrame.pivot的 docstring 中定义为 “What value combinations will be considered for the output table”输出表考虑哪些值组合类型为Sequence[Any] | pl.Series | pl.DataFrame。也就是说你声明哪些值结果的 schema 就包含哪些列查询在collect之前就能确定输出列。验证结果 schemaDataFrame和LazyFrame都有.collect_schema方法可以查看列名与数据类型schemas.md。对用on_columns声明过的查询这一点正是验证手段——在collect之前就能拿到静态输出 schemaprint(q.collect_schema())如果collect_schema()返回的列名与index列加上on_columns各值一致说明 schema 已按声明静态确定之后再q.collect()取结果。collect的输出以 LazyFrame.pivot docstring 中的文档示例为准下表中maths、physics两列名即来自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], ... indexname, ... valuestest_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),仅供参考