
在 polars 中,`df["col"]` 仅适用于 eager 模式且无法参与查询优化,而 `select`、`filter` 等表达式 api 可构建惰性执行计划,支持自动优化(如列裁剪、谓词下推),显著提升大数据场景下的性能与内存效率。
Polars 提供两种主要的数据操作范式:基于方括号的即时索引(eager indexing) 和 基于表达式的惰性计算(expression-based lazy evaluation)。二者在语义、执行时机和性能表现上存在本质差异。
✅ 方括号语法 df["col"] —— 简单但受限
- 仅作用于 DataFrame(eager 模式),不支持 LazyFrame;
- 立即执行:读取全部数据、加载整列、完成索引,无优化空间;
- 适合小规模探索性分析或快速调试,例如:
df = pl.DataFrame({"a": ["a", "b", "a"], "b": [2, 1, 1]}) print(df["a"]) # → Series('a', ['a', 'b', 'a'])
✅ 表达式 API(select, filter, with_columns, first 等)—— 高效且可组合
- 原生支持 LazyFrame,所有操作被记录为逻辑计划,延迟至 .collect() 才真正执行;
- 启用多项查询优化:列裁剪(只读所需列)、谓词下推(提前过滤行)、常量折叠、并行化等;
- 支持链式调用与跨列计算,语义更清晰、表达力更强。
以读取大型 CSV 文件首元素为例:
# ❌ eager + 方括号:强制加载全量数据(~700MB)
pl.read_csv("df.csv")["col"][0] # 耗时 ~200ms
# ✅ lazy + 表达式 API:仅扫描首行所需列
pl.scan_csv("df.csv").select("col").first().collect().item() # 耗时 ~300μs(快约 650×)? 关键洞察:性能差距并非来自 select vs [ ] 的语法本身,而是源于 lazy API 赋予的执行计划优化能力 —— scan_csv 不解析整文件,select("col") 避免读取无关列,first() 触发提前终止,三者协同实现亚毫秒级响应。
? 最佳实践建议
- 默认优先使用表达式 API:尤其在处理中大型数据(>10MB)、涉及 I/O(CSV/Parquet)、需链式变换(如 filter → group_by → agg)时;
- 避免混合 eager/lazy:不要在 LazyFrame 上调用 [](会报错),也不要对 DataFrame 过度依赖 select()(虽可用,但失去 lazy 优势);
-
调试时可 .explain() 查看优化效果:
plan = pl.scan_csv("df.csv").select("col").first() print(plan.explain()) # 输出优化后的物理执行计划 - 注意返回类型:df.select(...) 返回 DataFrame;lf.select(...).collect() 返回 DataFrame;而 lf.select(...) 本身返回 LazyFrame —— 明确区分阶段是掌握 Polars 的关键。
总之,方括号是 Python 风格的便捷入口,表达式 API 才是 Polars 高性能与声明式编程的核心载体。理解并善用 lazy evaluation,是你释放 Polars 全部潜力的第一步。










