10.1 与 pandas / NumPy / Arrow 互转
- to_pandas()
- Polars DataFrame → pandas DataFrame。默认会拷贝;若列都是 Arrow 兼容类型,可用
use_pyarrow_extension_array=True走零拷贝。 - pl.from_pandas()
- pandas → Polars。把 pandas 数据吸进 Arrow 内存。
- to_numpy()
- Polars → NumPy 数组。含 null 或多类型时会拷贝并可能升为 object,纯数值单列最高效。
- to_arrow() / pl.from_arrow()
- 与 Apache Arrow
Table互转,通常零拷贝——因为 Polars 内存本就是 Arrow 格式。 - 零拷贝(Zero-copy)
- 不复制底层内存、只共享缓冲区的转换。Arrow 生态内互转常能零拷贝,是 Polars 与 DuckDB/pandas(pyarrow backend) 高效协作的基础。
- PyArrow backend
- pandas 2.x 起可用 Arrow 作为后端存储,此时与 Polars 互转更省,且字符串/缺失值语义更一致。
import polars as pl
pdf = df.to_pandas() # → pandas
df2 = pl.from_pandas(pdf) # pandas → Polars
arr = df.to_numpy() # → NumPy
tbl = df.to_arrow() # → Arrow Table(零拷贝)
10.2 与 DuckDB 协作
DuckDB 与 Polars 都构建在 Arrow 上,可以零拷贝互喂:用 SQL 表达复杂查询,用 Polars 做表达式管道,各取所长。
import duckdb, polars as pl
df = pl.read_parquet("data.parquet")
# DuckDB 直接查询 Polars DataFrame(变量名即表名)
out = duckdb.sql("SELECT city, sum(sales) FROM df GROUP BY city").pl()
# .pl() 把结果转回 Polars DataFrame
10.3 Parquet 最佳实践
- 中间存储一律用 Parquet 而非 CSV:列式、带 schema、压缩率高、支持谓词/投影下推。
- 压缩选
zstd(压缩率与速度平衡好),归档可用更高 level。 - 大数据集分区落盘(按日期/地区目录),配合
scan_parquet+ filter 只读相关分区。 - 读大文件永远
scan_parquet(惰性)而非read_parquet(立即全读)。
df.write_parquet("out.parquet", compression="zstd")
# 分区写
df.write_parquet("dataset/", partition_by=["year", "region"])
# 惰性读一批分区文件并只取需要的
(pl.scan_parquet("dataset/**/*.parquet")
.filter(pl.col("year") == 2026)
.collect())
10.4 性能调优清单
1) 大数据用 Lazy + scan_*,让下推生效。
2) 中间存储用 Parquet,不用 CSV。
3) 用向量化表达式,禁用 map_elements 逐行回调。
4) 低基数字符串列转 Categorical,分组/连接更快、更省。
5) 一次 with_columns 塞多个表达式,让它们并行。
6) 别中途 collect,把链一路写到底。
7) 用 select/scan 的 columns 只取需要的列。
8) 超内存用 collect(engine="streaming") 或 sink_*。
9) 用 explain 确认下推生效。
10) 连接前检查键重复度,避免结果扇出爆炸。
10.5 从 pandas 迁移对照
| pandas | Polars |
|---|---|
df[df.a > 1] | df.filter(pl.col("a") > 1) |
df["c"] = df.a + df.b | df.with_columns((pl.col("a")+pl.col("b")).alias("c")) |
df.groupby("k").sum() | df.group_by("k").agg(pl.all().sum()) |
df.sort_values("a") | df.sort("a") |
pd.merge(a,b,on="k") | a.join(b, on="k") |
df.apply(f, axis=1) | 用表达式/when-then 重写(不要逐行) |
df.resample("1D").sum() | df.group_by_dynamic("t", every="1d").agg(...) |
10.6 常见坑
• 没有索引:Polars 无 pandas 那样的 Index,用普通列 + filter/join 代替 set_index/loc。
• null ≠ NaN:缺失是 null,浮点非数才是 NaN,二者需分别处理。
• group_by 无序:默认不保证行顺序,需要就 maintain_order=True 或后接 sort。
小数据(几万行)、一次性脚本、重度依赖 pandas 专有生态(如某些 sklearn/statsmodels 直接吃 pandas)时,pandas 依然够用。Polars 的收益在中大数据、生产管道、需要多核与惰性优化的场景最明显。
10.7 全教程总结
- Polars = Rust + Apache Arrow 列式内存 + 多线程 + 惰性查询优化,pandas 的现代替代。
- 核心是表达式 API:在 select/with_columns/filter/agg/over 各上下文中一以贯之。
- 生产管道用 Lazy + scan_ + sink_,让优化器与流式引擎为你省 IO 与内存。
- 与 pandas/NumPy/Arrow/DuckDB 无缝互转,Parquet 是最佳中间格式。
- 恭喜你读完 10 章——现在去用真实数据集把它跑起来,感受 10-100 倍的提速吧。