返回博客
Polars 与 pandas 在 Tick 级数据上的对比
把一条期货 tick 级数据流水线从 pandas 重写为 Polars 之后,内存、查询代价和踩过的坑。
2026-04-107 分钟阅读
PythonData Engineering
我最近把一条期货 L1/L2 数据入库流水线从 pandas 重写成 Polars。数据集大概 200 GB 的 Parquet,覆盖四年限价单簿快照。下面记录真正影响显著的点和没那么重要的点。
Polars 明显胜出的地方
- Lazy API 把 filter + group_by + join 合并成一次扫描,峰值内存从 32 GB 降到 6 GB 以内。
- 基于 Arrow 列的向量化运算比 pandas 同样的 group_by 聚合快 5–15 倍。
- Streaming 引擎可以处理超过内存的文件,无需手动分块。
提升有限的地方
对于需要 lookahead-aware 滚动窗口的逐行特征工程(例如对非对称窗口做因果滚动偏度),Polars 要求你以表达式的方式思考,最终代码长度和 pandas 版本差不多。这里赢在正确性,不在速度。
值得知道的坑
- Polars 默认 join 在不同版本间并不保证稳定——如果顺序重要,join 之后务必按确定性 key 重新排序。
- 处理不规则的 tick 时间时,pl.Expr.rolling 必须显式以时间而非行数指定窗口。
- dtype 之间的转换可能悄无声息地实例化整列;多用 explain()。
import polars as pl
lf = pl.scan_parquet("ticks/*.parquet")
(
lf.filter(pl.col("symbol").is_in(liquid_symbols))
.group_by(["symbol", pl.col("ts").dt.truncate("1m")])
.agg(
pl.col("price").last().alias("close"),
pl.col("price").std().alias("vol"),
)
.collect(streaming=True)
)我什么时候仍然用 pandas
小规模的交互式探索、Jupyter 上的草稿,以及任何需要只能接收 DataFrame 的旧库(部分老的 statsmodels 路径)。实践中的正确答案是两者并用:Polars 负责重活入库,pandas 负责混乱的建模对话。