模式
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 │
└─────┴──────┴──────┴──────┘