Polars vs Pandas 在生产 Pipeline 中的对比

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: Pandas作为Python数据处理基石,设计于单核时代;而Polars以Rust+Arrow重构架构,支持多线程惰性执行、列式存储与查询优化,10GB数据处理快94倍,是GB级ETL的现代之选。

大多数 Python 数据工程师最早学的是 pandas。因为它是行业标准,能用而且一直够用,所以一般也没人质疑过它。

Pandas 设计于 2008 年,面向的是那个时代的数据问题:假设每个操作都要立即返回结果,假设单个 CPU 核心足够,假设数据能放进内存。这些假设成立了很多年。随着 Pipeline 规模增长,它们越来越站不住脚。

这里说的并不是 pandas 好不好,因为它很好而且我现在也在用。现在的问题是问题在于它是否还匹配你实际在跑的工作负载。

对于超过约 1 GB 的文件型 ETL 来说,并不是pandas 出了问题,而是整个生态已经为这类工作产出了一个结构上更优越的工具——Polars。两者之间的差距不是量级上的小打小闹。

Polars 为何在结构上更快

谈基准测试数据之前,先搞清楚原理。下图并排展示了两种执行模型。

Pandas 的单线程即时执行(eager execution)vs. Polars 的多线程惰性执行(lazy execution)。

Pandas 的执行模型

Pandas 运行在 NumPy 之上,大多数操作是单线程的。Python 的全局解释器锁(GIL)阻止了并行执行,即便有多个线程可用。每个操作都立即执行,所以无论是否需要中间结果都会被创建并存入内存。对一个 5 GB 的 DataFrame 做五步变换,就会产生五份中间副本,内存占用迅速叠加。

Pandas 默认将字符串存储为 NumPy object 数组:每个值都是一个 Python 对象指针,每个唯一字符串大约占 67 字节,而列式存储只需 4 字节的额外开销。100 万个 18 字符的字符串,在 pandas object dtype 下约占 75 MB,同样的列在 Arrow 格式下约占 22 MB。

Polars 的执行模型

Polars 用 Rust 编写,完全运行在 GIL 之外。数据以 Apache Arrow 列式格式存储:每列是一块连续的类型化内存,对 CPU 缓存友好,也支持 SIMD 指令。调用

scan_parquet

时,不会读取任何数据。Polars 先构建逻辑执行计划,在触碰任何字节之前完成优化:谓词下推到扫描层、未使用的列在读取前裁剪、Join 顺序重排以提升效率。

执行采用 morsel 驱动模式。每个 CPU 线程取一块输入,用自己独立的本地状态处理,最后合并结果,计算过程中没有锁竞争,所有核心同时运行。

处理一个 10 GB Parquet 文件时,pandas 读取全部 10 GB,在单核上顺序处理,并在途中产生中间副本。同样的 Pipeline 在 Polars 中,只读取满足过滤和聚合所需的列和行组,在所有核心上并行处理,不会实体化任何不必要的中间结果。每次给 Pipeline 计时,这种差距都能感受到:pandas 已经在读取时,Polars 还在规划,但 Polars 先完成。

基准测试

下表汇总了不同规模和负载类型下的结果。

三个独立基准测试,分别对比了查询 Pipeline、生产 ETL 迁移和调度负载场景下 Polars 与 pandas 的表现。

PDS-H 基准测试

Polars 团队于 2025 年 5 月发布了更新的 PDS-H 测试结果,运行环境为 AWS c7a.24xlarge 实例(96 vCPU、192 GB RAM)。测试对 10 GB CSV 数据集运行全部 22 条 TPC-H 衍生查询。Polars 流式处理耗时 3.89 秒,pandas 2.2.3(启用 PyArrow dtype)耗时 365.71 秒——整条多步分析 Pipeline 下来,差距达到 94 倍。

在 Scale Factor 100(100 GB)的场景下,pandas 被直接排除在外。单线程执行加上缺乏查询优化器,导致在完成基准测试之前就触发了内存溢出(OOM)。Polars 流式处理耗时 23.94 秒。

这是厂商自己跑的基准测试,可以把它当作方向性参考。在普通硬件上的独立测试差距通常小一些,单个操作一般在 5 到 22 倍之间。那个标题级别的倍数是查询优化器和多线程在完整 Pipeline 中叠加后才出现的。

生产环境的实证

荷兰出行服务商 Check Technologies 在一个 Sprint 内将全部 100 多个 Airflow DAG 从 pandas 迁移到了 Polars。驱动力不是性能基准,而是最数据密集的 Pipeline 上反复出现的 OOM 错误。迁移耗时不到两周:最问题严重的 DAG 速度提升了 3.3 倍,几乎所有其他 DAG 提升约 2 倍,云基础设施成本降低了 25%。Check 的高级数据工程师 Paul Duvenage 表示,团队一旦切换到声明式表达式 API,迁移过程就非常顺畅。

DB Systel(德国铁路子公司)用 Polars 0.20 重写了一个列车调度重处理任务。该任务原本需要 96 分钟,Polars 版本只需 5.5 分钟——在真实生产负载上提升了 17.5 倍,而不是在合成基准上。

在小数据上,差距基本消失有时甚至会反转。Polars 的查询优化器存在规划开销,当数据集小于几百 MB 时,这个开销会超过计算节省。对于小 DataFrame 上的快速脚本pandas 写起来更快,跑起来也够快。

安装与运行

安装只需一条命令:

 # 创建项目并添加 Polars
 uv init polars-pipeline
 cd polars-pipeline
 uv add polars pyarrow      # 标准安装
 uv run pipeline.py

无需编译,无需系统依赖。Polars 以预编译 wheel 形式发布Rust 运行时已打包在内。

⚠️ 开始之前有一点值得注意:在 Apple Silicon(M 系列 Mac)上,标准 polars wheel 会触发 CPU 兼容性警告,并建议使用运行时兼容版本。

 # Apple Silicon:改用这个
 uv add "polars[rtcompat]" pyarrow

Linux 和 Intel Mac 上使用标准安装即可。在 M 系列硬件上,

polars[rtcompat]

可避免警告,并确保使用适合该处理器的正确 SIMD 指令。

并排对比:两个库实现相同操作

第一次看 Polars 代码时,语法感觉很陌生。表达式 API 需要一天时间适应,适应之后,发现它比 pandas 的等价写法更易读,而不是更难读。下面的代码执行完全相同的 ETL 变换:读取 Parquet 文件、过滤行、按类别聚合、排序结果。先是 pandas 版本,然后是 Polars LazyFrame 版本。

 # pandas 版本
importpandasaspd
importtime

start=time.perf_counter()

df=pd.read_parquet("sales.parquet")
result= (
    df[df["revenue"] >1000]
    .groupby("category")
    .agg(
        total_revenue=("revenue", "sum"),
        avg_price=("price", "mean"),
        order_count=("order_id", "count"),
    )
    .sort_values("total_revenue", ascending=False)
    .reset_index()
)

print(f"pandas: {time.perf_counter() -start:.3f}s")
 print(result)
 # Polars 版本——带谓词下推和投影下推的惰性执行
importpolarsaspl
importtime

start=time.perf_counter()

result= (
    pl.scan_parquet("sales.parquet")          # 此时不读取任何数据
    .filter(pl.col("revenue") >1000)         # 下推到扫描层
    .group_by("category")
    .agg(
        total_revenue=pl.col("revenue").sum(),
        avg_price=pl.col("price").mean(),
        order_count=pl.col("order_id").count(),
    )
    .sort("total_revenue", descending=True)
    .collect()                                 # 执行在这里发生
)

print(f"Polars: {time.perf_counter() -start:.3f}s")
 print(result)

结构上的关键差异在于

scan_parquet

对比

read_parquet

。Pandas 版本立即读取整个文件;Polars 版本构建执行计划,只读取满足过滤和聚合所需的行和列。对于一个 1 GB、20 列、实际只需要 3 列的文件,Polars 读取的字节数可能不到 pandas 的 20%。

流式处理超出内存容量的数据

当数据集超过可用内存时,在

collect

中加入

engine="streaming"

。Polars 以称为 morsel 的批次处理数据,自适应地溢出到磁盘,始终不将完整数据集保留在内存中。

 result= (
     pl.scan_parquet("large_dataset/*.parquet")
     .filter(pl.col("status") =="active")
     .group_by("region")
     .agg(pl.col("amount").sum())
     .sort("amount", descending=True)
     .collect(engine="streaming")              # 核外执行
 )

如需直接写入磁盘而完全不在内存中实体化,使用

sink_parquet

 (
     pl.scan_parquet("raw/*.parquet")
     .filter(pl.col("error_code").is_null())
     .sink_parquet("clean/output.parquet")     # 分批流式写入磁盘
 )

生产环境注意事项

在生产环境中显式设置线程数,以避免与其他进程争抢资源:

 importos
 os.environ["POLARS_MAX_THREADS"] ="8"       # 必须在导入 polars 之前设置
 importpolarsaspl                           # Polars 在导入时初始化线程池——
                                               # 导入后再设置此变量无效

pyproject.toml

中锁定 Polars 版本。1.x API 已稳定,但小版本更新会引入新特性,在边缘情况下可能改变行为。锁定版本,在与生产 OS 一致的容器中测试,有意识地升级。

Pandas 仍然占优的场景

Polars 是 1 GB 以上文件型 ETL 的更好选择,下图按数据规模和负载类型梳理了决策框架。

按数据规模和负载类型选择工具,并明确标注了机器学习生态系统的约束。

大多数机器学习库以 pandas DataFrame 作为原生输入格式。scikit-learn、statsmodels 以及很多绘图库,要么明确要求 pandas,要么默认如此。为了避免一次

.to_pandas()

调用而重写整个技术栈,这笔买卖不值得做。

在每一个需要给模型喂数据的 Pipeline 中,实践中的做法是混合方案:用 Polars 做繁重的计算工作,最后一步再转换:

 # 用 Polars 做重活
features= (
    pl.scan_parquet("events/*.parquet")
    .group_by("user_id")
    .agg([
        pl.col("session_duration").mean().alias("avg_session"),
        pl.col("purchase").sum().alias("total_purchases"),
        pl.col("event_date").max().alias("last_seen"),
    ])
    .collect(engine="streaming")
)

# 在边界处零拷贝转换
importsklearn
 X=features.to_pandas()                     # 基于 Arrow,几乎瞬间完成

转换几乎瞬间完成,因为 Polars 和新版 pandas 共享 Apache Arrow 内存格式——当两边都使用 Arrow 类型时,不会发生数据拷贝。

Pandas 3.0 带来了什么变化

2026 年 1 月发布的 pandas 3.0,将 PyArrow 支持的字符串设为字符串列的默认类型,并将写时复制(Copy-on-Write)设为唯一执行模式。这些改动使字符串密集型数据集的内存占用降低了最多 70%,并消除了一类静默的变异 bug。

这是真实的改进。它在 I/O 和内存方面实质性地缩小了差距。但多核执行的差距依然存在——pandas 的聚合操作在任何版本中仍然是单线程、即时执行的,也没有查询优化器。如果瓶颈是计算而非内存,3.0 版本并没有改变这一判断。

总结

有三个信号说明一条 Pipeline 已经到了该迁移的时候:

第一:在生产规模的数据上触发 OOM,或者已经为了绕过内存限制加入了分块逻辑。第二:本该几秒完成的任务跑了好几分钟,性能分析显示 pandas 的 groupby 或 join 操作占据了主要运行时间。第三:运行在一台多核机器上,执行期间那些 CPU 核心基本闲着。

迁移的时候可以选最慢的那条Pipeline或者最常 OOM 的那条。只用 Polars LazyFrame 重写计算密集的部分,在输出端保留 pandas 边界以衔接机器学习或绘图,然后在生产规模的数据上基准测试,再推上线。如果在超过 1 GB 的数据集上看不到至少 3 倍的提升瓶颈可能根本不在 DataFrame 库上。

Pandas 不是遗留技术,它是精准的专用工具;Polars 是另一种工作的精准专用工具。为每项工作选择合适的,不是迁移项目,是工程判断力。

https://avoid.overfit.cn/post/da28f678d72c42729ccef7af469c1731

作者:Nevenka Lukic

目录
相关文章
|
28天前
|
人工智能 Oracle 机器人
推理 → 行动 → 观察:用 LangChain + Python 实现一个智能体循环
智能体循环(Agentic Loop)突破单次问答局限,通过“推理→行动→观察”迭代闭环,让AI能自主分解任务、调用工具、持续优化直至目标完成,是构建真正自动化智能体的核心架构。
294 9
推理 → 行动 → 观察:用 LangChain + Python 实现一个智能体循环
|
28天前
|
弹性计算 监控 Java
Maven 并行构建配置:-T 4C 提速 4 倍实战
本文深入讲解了 Maven 并行构建的核心原理和实战技巧,包含 -T 参数详解、模块并行化改造、性能监控与分析等企业级最佳实践。通过真实案例展示了如何将多模块项目的构建时间从 45 分钟缩短到 11 分钟(提升 4.1 倍),提供完整的性能测试脚本和优化检查清单。掌握这些技能,你将能够充分利用多核 CPU 加速 Maven 构建。适合 Java 开发者、架构师、DevOps 工程师阅读。
|
28天前
|
机器学习/深度学习 数据采集 人工智能
田间杂草检测数据集分享(适用于YOLO系列深度学习分类检测任务)
本数据集含4000张真实农田图像(小麦/玉米/水稻田),YOLO格式标注杂草目标,覆盖多天气、光照与视角,适用于YOLO系列等目标检测模型训练,助力智能除草与精准农业研究。(239字)
363 16
|
27天前
|
人工智能 缓存 JavaScript
2026 年开源 Agent 工具包选型指南:延迟、审计、可移植性与语言栈
本文系统梳理2026年构建AI Agent的7层开源工具栈,围绕四大核心约束——延迟预算、审计追踪、模型可移植性与语言栈(Python/TS),对比LangGraph、CrewAI、Mem0、Zep、OpenHands、Langfuse、vLLM等主流方案的适用场景、替换成本及开源性质,助力团队按需选型,避免“一刀切”组合陷阱。
302 1
2026 年开源 Agent 工具包选型指南:延迟、审计、可移植性与语言栈
|
28天前
|
JSON 人工智能 测试技术
我如何用Skills+Postman,让接口测试用例自动生成、自动维护,半年零手工更新
本文揭秘如何用Postman+大模型Skills实现接口测试用例“零手工维护”:通过自动感知OpenAPI变更、智能生成并应用Collection补丁、Git化管理+CI闭环验证,6个月未手动增删改用例。核心不是生成用例,而是让用例随代码自动同步。
|
24天前
|
人工智能 弹性计算 API
OpenClaw+阿里云百炼Token Plan 一站式部署与配置流程
OpenClaw作为一款开源可自托管的AI智能体执行框架,能让大模型从单纯对话升级为可执行文件处理、代码编写、流程自动化等任务的数字助手。在阿里云上部署OpenClaw并接入百炼Token Plan,可依托阿里云稳定的云服务与百炼的大模型能力,打造专属、高效、低成本的AI智能体服务。本文将从准备工作、阿里云服务器部署、百炼Token Plan开通与密钥获取、OpenClaw配置、功能验证到常见问题排查,提供完整实操流程,帮助用户快速完成部署与配置。
244 9
|
28天前
|
算法 测试技术 PyTorch
在 AMD ROCm DSW 上部署 Qwen3.6-27B-FP8:vLLM、MTP 解码加速与小并发压测
本文记录一次在 ModelScope DSW AMD GPU 实例上完成的 Qwen3.6-27B-FP8 推理实践。实验重点不是单纯证明模型可以启动,而是围绕 vLLM ROCm 服务、Qwen MTP 投机解码、near-8K 长上下文正确性验证、FP8 KV cache 和小并发 serving 压测,整理一套可复现、可复查、可继续扩展的 AMD GPU 大模型推理 baseline。
666 0
|
2月前
|
消息中间件 网络协议 测试技术
socket长连接在手游场景下的技术实践
本文介绍了37手游基于B站goim框架自研长连接系统的实践。系统采用分层设计,支持多协议和发布/订阅机制,用于直播弹幕、实时推送等场景,实现了高性能与业务适配。
200 4
socket长连接在手游场景下的技术实践
|
2月前
|
人工智能 定位技术 数据库
2026 RAG 选型指南:Vector、Graph、Vectorless 该怎么挑
2026 RAG选型指南指出:Vector RAG已难胜任复杂场景;GraphRAG通过知识图谱支撑多跳关系推理,Vectorless RAG则摒弃向量库,依托文档树结构+LLM导航实现高精度定位。三者非替代,而应按问题类型智能路由——Adaptive RAG成企业新范式。
316 3
2026 RAG 选型指南:Vector、Graph、Vectorless 该怎么挑
|
2月前
|
人工智能 自然语言处理 供应链
为什么 MCP 在协议层会有 prompt injection的问题:工具描述如何劫持 agent 上下文
MCP(Model Context Protocol)虽成AI Agent主流集成标准,但其将工具描述全量注入上下文的设计,导致“Context Poisoning”——恶意指令可借工具元数据污染LLM推理。OWASP将其列为LLM应用头号漏洞,2025年已致超10万站点遭袭。根本风险在于协议层信任模型缺失,非清洗不可用。
207 12
为什么 MCP 在协议层会有 prompt injection的问题:工具描述如何劫持 agent 上下文