Chapter 01

认识 Polars 与安装

搞清 Polars 为何能比 pandas 快一到两个数量级,理解 Apache Arrow 列式内存与 Rust 无 GIL 多线程,建立 eager / lazy 两套心智模型,并跑通第一个例子。

1.1 pandas 的时代局限

pandas 是 Python 数据分析的绝对基石,但它诞生于 2008 年,架构决定了它今天的几个硬伤:

1.2 Polars 是什么

Polars 是用 Rust 从零编写的 DataFrame 库,通过 PyO3 暴露 Python 接口。它不是给 pandas 打补丁,而是重新设计了整个执行引擎:列式内存、多线程、惰性优化。相同的分析任务,Polars 常常比 pandas 快 10 到 100 倍,内存占用也更低。

DataFrame
二维表格数据结构,由若干具名的列(Series)组成,每列类型一致。是 Polars 最常用的容器。
Series
一维、类型统一的具名数组,是 DataFrame 的一列。底层是一个或多个 Arrow ChunkedArray
Apache Arrow
一种跨语言的列式内存格式标准。同一列数据在内存中连续排列,缓存友好、便于 SIMD 向量化,且可在 Polars/pandas/DuckDB/Spark 间零拷贝传递。
列式存储(Columnar)
与"行式"相对。分析型查询通常只碰少数几列,列式布局能只读取需要的列,且同列数据同质、压缩率高、向量化快。
GIL(全局解释器锁)
CPython 的机制,保证同一时刻只有一个线程执行 Python 字节码。它让纯 Python 难以真正并行。Polars 的计算在 Rust 层完成、绕开了 GIL,因此能真正多线程并行。
Eager 执行
"立即执行"模式:写一行代码就立刻算出结果,交互式探索直观,但每步都物化中间结果,无法整体优化。
Lazy 执行
"惰性执行"模式:先把一系列操作记录成查询计划,调用 collect() 时才交给优化器整体优化并执行。是 Polars 的性能杀手锏。
查询优化器(Query Optimizer)
在 Lazy 模式下分析查询计划、自动重写以减少工作量,如谓词下推、投影下推、公共子表达式消除等——类似数据库的优化器。

1.3 为什么这么快

维度pandasPolars
内核语言Python + C(NumPy)Rust
内存格式NumPy(混合/行影响)Apache Arrow 列式
并行单线程(受 GIL)多线程(无 GIL)
执行模型EagerEager + Lazy 优化
字符串object 数组,慢Arrow Utf8,快
大于内存❌ 内存不够就崩✅ streaming 流式
缺失值NaN / None 混用统一 null 位图
SIMD 是什么

SIMD(Single Instruction Multiple Data,单指令多数据)是 CPU 一次对一组连续数据做同样运算的能力。列式内存把同类型数据连续排列,恰好让编译器能生成 SIMD 指令,一条指令处理 4/8/16 个数,这是列式引擎快的底层原因之一。

1.4 安装

# 推荐用 pip 安装(含常用可选功能)
$ pip install polars

# 想要全部可选功能(Excel、数据库、云存储、绘图等)
$ pip install 'polars[all]'

# 用 uv(更快的包管理器)
$ uv add polars

# 老 CPU(不支持 AVX2)请装兼容版
$ pip install polars-lts-cpu
版本说明

本教程基于 Polars 1.x(2024 年后的稳定 API)。若你查到旧文档里 groupby(无下划线)、pl.count() 等写法,那是 0.x 老 API,本教程一律使用现代写法如 group_bypl.len()

1.5 第一个例子:Hello Polars

import polars as pl

# 从字典创建 DataFrame
df = pl.DataFrame({
    "name": ["Alice", "Bob", "Carol"],
    "age": [30, 25, 35],
    "city": ["北京", "上海", "北京"],
})

print(df)
# shape: (3, 3)
# ┌───────┬─────┬──────┐
# │ name  ┆ age ┆ city │
# │ ---   ┆ --- ┆ ---  │
# │ str   ┆ i64 ┆ str  │
# ╞═══════╪═════╪══════╡
# │ Alice ┆ 30  ┆ 北京 │
# │ Bob   ┆ 25  ┆ 上海 │
# │ Carol ┆ 35  ┆ 北京 │
# └───────┴─────┴──────┘

注意打印结果里每列上方的 str/i64——这是列的 dtype(数据类型)。Polars 的表格默认会显示 shape 和类型,比 pandas 更信息密集。

1.6 Eager vs Lazy 初体验

# Eager:每步立即执行
result = (
    df.filter(pl.col("age") > 28)
      .select(["name", "city"])
)

# Lazy:先构建计划,collect() 才执行 + 优化
result = (
    df.lazy()
      .filter(pl.col("age") > 28)
      .select(["name", "city"])
      .collect()
)
心智模型

探索数据、写 Notebook → 用 Eager(直观)。生产管道、大数据、读文件 → 用 Lazyscan_* + collect),让优化器帮你少读列、少扫行。第 7 章会深入讲 Lazy。

1.7 小结与下一步