Python Polars扫描CSV与读取CSV有什么区别
来源:17golang原创
时间:2026-10-13 20:10:01 407浏览 收藏
在 Polars 里,read_csv 和 scan_csv 都能处理 CSV,但它们把“读取”和“执行”放在了不同位置:read_csv 直接返回已经读取的 DataFrame;scan_csv 返回描述查询的 LazyFrame,真正读取通常等到 collect()。如果后面还要继续筛选列、过滤行或聚合,优先考虑扫描;如果正在探索数据、需要马上查看中间结果,直接读取更顺手。
官方地址:https://docs.pola.rs/user-guide/io/csv/
可以把两者理解成两种调用方契约:read_csv承诺“现在给我一张表”,scan_csv承诺“先把查询描述好,最后统一执行”。差别不在 CSV 格式,而在 LazyFrame 是否保留了优化查询的机会。
先区分返回对象和执行时机
我第一次把 Polars 用在批量 CSV 清洗时,最容易混淆的是两个函数都看起来像“打开文件”。实际上,read_csv 的返回值是 DataFrame,调用点就会开始解析文件;scan_csv 的返回值是 LazyFrame,它先保存数据源和后续表达式。
import polars as pl
# 直接读取:调用结束时已经得到内存中的 DataFrame。
eager_df = pl.read_csv("sales.csv")
print(eager_df.head())
# 延迟扫描:这里只建立查询描述,不把结果收集成 DataFrame。
lazy_query = pl.scan_csv("sales.csv")
# collect 才是执行边界,返回最终的 DataFrame。
result_df = lazy_query.select(["region", "amount"]).collect()
print(result_df.head())
因此,scan_csv 并不是“把整个 CSV 读进来后换一种对象包装”。它延后了解析和查询执行,让后续的 select、filter、group_by 可以一起交给查询计划。

scan_csv 的价值在于把查询一起交给优化器
官方文档把扫描 CSV 描述为延迟解析,并指出查询优化器可以把谓词和投影下推到扫描层。简单说,过滤条件可能尽量提前应用,列选择也可以让扫描只关注需要的列,从而减少不必要的读取、内存和计算。
import polars as pl
# 先描述完整查询:只保留后续真正需要的列和行。
query = (
pl.scan_csv("sales.csv")
.select(["region", "amount"])
.filter(pl.col("amount") > 1000)
.group_by("region")
.agg(pl.col("amount").sum().alias("total_amount"))
)
# 统一执行查询;此前的链式调用仍然只是 LazyFrame 描述。
summary = query.collect()
print(summary)
这里的收益有一个边界:只有仍处于 LazyFrame 查询中的操作,优化器才有机会统一安排。若中途已经 collect(),后续操作就是针对 DataFrame 的新一轮处理,前面的扫描范围不会再被后面的条件缩小。

按调用方需求选择 read_csv 还是 scan_csv
如果任务是临时查看文件、交互式探索,或者你必须在每一步观察中间表,read_csv 的直接反馈更符合调用方预期。它少一个执行边界,代码也更短。
如果任务是固定的数据管道,例如读取后只留几列、过滤一部分行再聚合,scan_csv 更适合。它的核心不是保证任何数据集都更快,而是保留优化器重新安排查询的空间。
| 需求 | 建议 | 原因 |
|---|---|---|
| 马上查看列名和样例 | read_csv | 调用后直接得到 DataFrame |
| 多步过滤、选列、聚合 | scan_csv | 可以统一形成 LazyFrame 查询 |
| 需要中间结果参与分支判断 | read_csv 或提前 collect | 调用方确实需要立即拿到数据 |
| 想确认优化是否生效 | scan_csv(...).filter(...).explain() | 直接查看查询计划文本 |
用 explain 复查计划,而不是凭感觉猜性能
扫描模式的性能优势不能只靠函数名判断。把查询交给 explain(),可以查看计划中是否出现需要的列数、过滤条件和 CSV scan 节点:
import polars as pl
# explain 只展示计划,适合检查优化器看到的查询形状。
query = (
pl.scan_csv("sales.csv")
.filter(pl.col("amount") > 1000)
.select(["region", "amount"])
)
print(query.explain())
# 真正需要结果时再执行,并把执行边界集中在这里。
result = query.collect()
常见误区有三个:把 scan_csv 当成自动分块读取;在很早的位置调用 collect(),让后面的过滤失去下推机会;为了“更快”而忽略必须立即查看中间结果的业务需求。正确选择应由查询形状和调用方时机共同决定。
相关问题
scan_csv 调用后是不是已经把文件读进内存了?
不应这样理解。它先返回 LazyFrame 并延后实际解析,通常在 collect() 等执行动作发生时才运行查询。
所有 CSV 都应该改成 scan_csv 吗?
不是。探索数据、需要中间结果或查询很简单时,read_csv 更直接;固定的多步查询才更适合先扫描再统一收集。
怎样知道过滤和选列是否被下推?
对 LazyFrame 调用 explain() 查看查询计划,关注扫描节点、投影列数和过滤条件,而不是只比较函数名称。
-
361 收藏
-
346 收藏
-
235 收藏
-
251 收藏
-
407 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习