模式
Polars 的 DataFrame
或 LazyFrame
的模式规定了列的名称及其数据类型。您可以使用 DataFrame
或 LazyFrame
上的 .collect_schema
方法查看模式。
lf = pl.LazyFrame({"foo": ["a", "b", "c"], "bar": [0, 1, 2]})
print(lf.collect_schema())
Schema({'foo': String, 'bar': Int64})
模式在惰性API中扮演着重要角色。
惰性API中的类型检查
惰性API的一个优点是,Polars 会在处理任何数据之前检查模式。此检查发生在您执行惰性查询时。
我们通过以下简单示例了解其工作原理,我们在字符串列 foo
上调用了 .round
表达式。
lf = pl.LazyFrame({"foo": ["a", "b", "c"]}).with_columns(pl.col("foo").round(2))
.round
表达式仅对数值数据类型的列有效。在字符串列上调用 .round
意味着当您使用 collect
评估查询时,该操作将引发 InvalidOperationError
错误。此模式检查发生在调用 collect
时,即在数据处理之前。
try:
print(lf.collect())
except Exception as e:
print(f"{type(e).__name__}: {e}")
InvalidOperationError: round can only be used on numeric types
如果我们在急切模式下执行此查询,则只有在数据完成所有早期步骤的处理后,才会发现错误。
当我们执行惰性查询时,Polars 会在实际处理管道中数据这一耗时步骤之前,检查任何潜在的 InvalidOperationError
。
惰性API必须知道模式
在惰性API中,Polars 查询优化器必须能够在查询计划的每一步推断模式。这意味着模式无法提前知晓的操作不能与惰性API一起使用。
模式无法提前知晓的经典操作示例是 .pivot
(透视)操作。在 .pivot
中,新列名来自其中一列中的数据。由于这些列名无法提前知道,因此 .pivot
在惰性API中不可用。
处理惰性API中不可用的操作
如果您的管道包含一个在惰性API中不可用的操作,通常最好的做法是:
- 在该点之前以惰性模式运行管道
- 使用
.collect
执行管道,以具体化一个DataFrame
- 在
DataFrame
上执行非惰性操作 - 使用
.lazy
将输出转换回LazyFrame
,然后继续在惰性模式下操作
我们在这个示例中展示了如何处理非惰性操作,具体步骤如下:
- 创建一个简单的
DataFrame
- 使用
.lazy
将其转换为LazyFrame
- 使用
.with_columns
进行转换 - 在透视操作之前使用
.collect
执行查询以获取一个DataFrame
- 在
DataFrame
上执行.pivot
- 转换回惰性模式
- 执行
.filter
- 最后使用
.collect
执行查询以获取一个DataFrame
collect
· lazy
· pivot
· filter
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)
shape: (2, 4)
┌─────┬──────┬──────┬──────┐
│ id ┆ jan ┆ feb ┆ mar │
│ --- ┆ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 ┆ i64 │
╞═════╪══════╪══════╪══════╡
│ a ┆ 0 ┆ null ┆ null │
│ b ┆ null ┆ 2 ┆ null │
└─────┴──────┴──────┴──────┘