polars中的read、scan和sink有什么区别?

2 投票
1 回答
69 浏览
提问于 2025-04-13 16:21

在Polars这个工具里,我们有三种方法可以用来输入数据,分别是 readscansink

而输出数据时,我们用的是 write

那么 readscansink 这三者有什么区别呢?

https://docs.pola.rs/py-polars/html/reference/io.html

这里是图片描述

1 个回答

4

你可以把 scan 想象成一种 “懒读取”,而 sink 则是 “懒写入”

我们以一个 CSV 文件为例:

df = pl.read_csv("https://github.com/pola-rs/polars/raw/main/py-polars/tests/unit/io/files/foods1.csv")
df.write_csv("foods1.csv")

read 是一种急切的方式,会把所有内容都加载到内存中,给你一个数据框(DataFrame)。

>>> pl.read_csv("foods1.csv")
shape: (27, 4)
┌────────────┬──────────┬────────┬──────────┐
│ category   ┆ calories ┆ fats_g ┆ sugars_g │
│ ---        ┆ ---      ┆ ---    ┆ ---      │
│ str        ┆ i64      ┆ f64    ┆ i64      │
╞════════════╪══════════╪════════╪══════════╡
│ vegetables ┆ 45       ┆ 0.5    ┆ 2        │
│ seafood    ┆ 150      ┆ 5.0    ┆ 0        │
│ meat       ┆ 100      ┆ 5.0    ┆ 0        │
│ fruit      ┆ 60       ┆ 0.0    ┆ 11       │
│ seafood    ┆ 140      ┆ 5.0    ┆ 1        │
│ …          ┆ …        ┆ …      ┆ …        │
│ seafood    ┆ 130      ┆ 1.5    ┆ 0        │
│ fruit      ┆ 130      ┆ 0.0    ┆ 25       │
│ meat       ┆ 100      ┆ 7.0    ┆ 0        │
│ vegetables ┆ 30       ┆ 0.0    ┆ 5        │
│ fruit      ┆ 50       ┆ 0.0    ┆ 11       │
└────────────┴──────────┴────────┴──────────┘

LazyFrame

scan 则给我们一个 LazyFrame。

>>> pl.scan_csv("foods1.csv")
<LazyFrame [4 cols, {"category": String … "sugars_g": Int64}] at 0x12E720880>

我们可以使用 LazyFrame.explain() 来获取查询计划的信息。

>>> print(pl.scan_csv("foods1.csv").explain())

  Csv SCAN foods1.csv
  PROJECT */4 COLUMNS

优化

当使用 Polars 的懒惰 API 时,“Polars 会对你的查询进行多种优化”

如果我们选择了一部分列,看看计划是如何变化的:

>>> print(pl.scan_csv("foods1.csv").select("category", "fats_g").explain())
FAST_PROJECT: [category, fats_g]

    Csv SCAN foods1.csv
    PROJECT 2/4 COLUMNS

如果我们添加一些表达式:

print(
   pl.scan_csv("foods1.csv")
     .select(pl.col("category") + "_foo", pl.col("category") + "_foo", "fats_g")
     .explain()
)
 SELECT [
         col("__POLARS_CSER_2614548871777405161").alias("category"), 
         col("__POLARS_CSER_2614548871777405161").alias("category"), 
         col("fats_g"), 
         col("category").str.concat_horizontal([String(_foo)]).alias("__POLARS_CSER_2614548871777405161")
 ] FROM

    Csv SCAN foods1.csv
    PROJECT 2/4 COLUMNS

优化器发现 pl.col("category") + "_foo" 被重复使用了。

这让它只需要执行一次,并将结果缓存到一个临时列中。(在这个例子中是 __POLARS_CSER_2614548871777405161

流式 API

Polars 还有一个流式引擎,sink 方法就是使用这个引擎:

例如,来自 .sink_csv() 的文档:

以流式模式评估查询并写入 CSV 文件。

这允许将 大于内存 的流式结果写入磁盘。

流式模式被认为是 不稳定 的。它可能在任何时候发生变化,而不会被视为破坏性更改。

撰写回答