Pandas 与 Polars:语法、性能和资源占用方面的对比

1. 为什么要把这两个放在一起比

pandas 在 Python 里做数据处理差不多是"事实标准"了,十多年积累下来的生态和社区,几乎你搜到的教程、现成代码都是它。

Polars 是这两年冒出来的新选手,主打更快、更省内存、写法更干净。

于是很多人会纠结一个问题:Polars 到底比 pandas 强多少,值不值得花时间学?

本文用一份门店销售明细的模拟数据,从三个最关心的角度:语法怎么写、跑起来有多快(性能)、吃多少内存(资源占用)。把两者摆到同一张桌子上实测。所有数字都是我在本机真实跑出来的,你可以按文末的方式在自己的机器上测试。

2. 准备环境和测试数据

先装依赖,只要三个:

bash 复制代码
pip install pandas polars psutil

psutil 是用来测内存增量的,剩下两个是主角。版本是 pandas 2.3.3 / polars 1.33.1,不同版本速度会有出入,但量级关系不会变。

数据用一份门店销售明细来模拟,比英文教程里那些营养成分表更贴近国内常见的经营分析场景。

字段就六个:订单号、门店、品类、销售额、数量、日期。

生成逻辑在 gen_data.py 里,固定了随机种子,你跑出来的数据和下面我用的完全一致。核心片段长这样:

python 复制代码
rng = np.random.default_rng(42)
store = rng.choice(["北京朝阳店","上海浦东店","广州天河店","深圳南山店","成都武侯店"], n)
category = rng.choice(["奶茶","咖啡","甜品","小食"], n)
amount = np.round(rng.uniform(8.0, 68.0, n), 2)

默认造 200 万行,约 100MB 的 CSV。想用小数据量对比也行,改个参数即可。

3. 读 CSV 的速度(性能)

最直观的性能对比就是读文件。同样一份 100MB 的 CSV,分别用两个库读进来计时:

python 复制代码
t = time.time(); df_pd = pd.read_csv(CSV); pd_t = time.time() - t
t = time.time(); df_pl = pl.read_csv(CSV); pl_t = time.time() - t

本机结果:pandas 1.634s,polars 0.130s,加速比约 12.5 倍。

差距主要来自 pandas 的 CSV 解析是单线程的,而 Polars 会自动把读取并行到多个 CPU 核心上。

这里有个我实测出来的坑要提醒你:不要一上来就用很小的文件比。

我先用过 50 万行试,两者几乎一样快、甚至 pandas 还略快一点。Polars 的多核优势要在文件足够大、或者管道足够复杂时才明显。

所以你要评估自己真实场景的数据量,别被小样本误导。

4. 内存占用的差别(资源占用)

资源占用主要看内存。

我在独立子进程里测"跑完同一条流水线前后的 RSS 增量",避免 Python 内存分配器不归还内存带来的干扰:

python 复制代码
proc = psutil.Process(os.getpid())
base = proc.memory_info().rss
df = read_fun(CSV); df = df.filter(...).group_by(...).agg(...)
delta = proc.memory_info().rss - base

结果有点反直觉:这组简单的窄表上,pandas 增量 281.6MB,polars 341.7MB,两者接近、polars 还略高一点。

原因在于:Polars 真正省内存的场景不是"简单读一个窄表",而是复杂管道里靠惰性求值砍掉中间副本(第 7 节会讲)。

所以**"Polars 更省内存"这句话得加前提**,否则容易翻车。

5. 基础操作的写法差异(语法)

语法是日常写代码最直观的差别,挑三个最常用的操作看。

选列 :pandas 用括号加列名列表,Polars 用 .select(),表达更接近"我要什么"而不是"怎么取":

python 复制代码
# pandas
sub = df[["store", "amount"]]
# polars
sub = df.select(["store", "amount"])

过滤 :pandas 是布尔索引,Polars 的 .filter() 读起来更像 SQL:

python 复制代码
# pandas
hot = df[df["amount"] > 30]
# polars
hot = df.filter(pl.col("amount") > 30)

加列:这是最该注意的一点------pandas 默认原地修改,Polars 默认返回新表、不改动原表(不可变):

python 复制代码
# pandas:原地改,df 本身变了
df["bonus"] = df["amount"] * 0.1
# polars:返回新 DataFrame,原 df 不变
df2 = df.with_columns((pl.col("amount") * 0.1).alias("bonus"))

写法孰优孰劣见仁见智,但 Polars 的不可变默认能减少很多"改了上游、下游莫名其妙出错"的 bug。

6. 分组聚合的速度(性能)

分组聚合是经营分析里天天干的活:按门店汇总销售额。这里按门店对销售额求均值、中位数、标准差,同时对数量求均值:

python 复制代码
# pandas
g = df.groupby("store")["amount"].agg(["mean","median","std"])
# polars
g = df.group_by("store").agg(
    pl.col("amount").mean().alias("mean"),
    pl.col("amount").median().alias("median"),
    pl.col("amount").std().alias("std"),
)

本机结果:pandas 0.072s,polars 0.018s,加速比约 4.1 倍。

语法上 pandas 用字典描述聚合更紧凑,但要多一步 reset_index() 和手动改名;

Polars 链式写法啰嗦一点但可读性更好。

7. Polars 的惰性求值(资源 + 性能优化)

Polars 有个 pandas 没有的杀手锏:惰性求值。

用 scan_csv 只是先"画好查询计划"而不真读数据,把过滤、分组、聚合全串起来,只有调用 .collect() 才真正执行;执行前 Polars 会重排整合整条查询,把能下推的过滤提前,还能省掉中间结果的复制。

python 复制代码
q = (pl.scan_csv(CSV)
        .filter(pl.col("amount") > 30)
        .group_by("store")
        .agg(pl.col("amount").mean().alias("avg")))
result = q.collect()

光说"省内存"不够直观,我把它和第 4 节那组基准放在同一个管道上实测了一遍。

管道是:读 CSV → 过滤掉小额订单 → 派生两个列(revenue = 销售额 × 数量、cost = revenue × 0.3)→ 按门店分组聚合 → 排序。

普通模式(不管是 pandas 还是 polars)会老老实实把派生列物化成一个 200 万行的大中间表;

惰性模式则把过滤、派生、分组融合成一步,只在最后聚合时才算,不保留整列副本。

三种模式各跑在独立进程里测峰值内存,结果:

模式 峰值内存增量
pandas(普通) 365.7 MB
polars(普通) 360.8 MB
polars(惰性) 218.4 MB

差距很清楚:两个普通模式都在 360MB 上下,惰性模式只要 218.4MB,省了约 40%。

原因就是上面说的:普通模式在内存里多撑了一张 200 万行 × 2 列的派生表,惰性模式把它融合掉了。

注意这里省的是**"中间副本"**,不是读取本身;所以第 4 节那种"只读不怎么算"的窄表里两者才会看起来差不多,一旦管道变长、派生列变多,惰性的内存优势就出来了。

这段对比的完整代码在 benchmark.py 里(函数 pipeline_mem_peak),想在自己机器上验证,直接跑 python benchmark.py 就会打印上面这张表。

8. 怎么选

把三个维度收一下:

  1. 语法上: Polars 更声明式、默认不可变,pandas 更熟悉、可原地改;
  2. 性能上:大文件 / 复杂管道 Polars 明显更快(本机读取 12.5 倍、聚合 4.1 倍),小文件两者差不多;
  3. 资源占用上:简单任务两者接近,复杂任务靠 Polars 惰性求值才显出省内存的优势。

如果你在做大规模分析、数据工程、或者某条慢管道卡性能,优先试 Polars;如果项目吃 pandas 生态、要快速 exploratory 分析、或者团队都在用,pandas 仍是稳妥选择。

两者语法差异不算大,迁移成本可控,拿一条你自己的慢管道先试水最实在。

文中的用到的代码 gen_data.py和benchmark.py共享在:pandas-vs-polars-code.zip url11.ctfile.com/f/45455611-...

相关推荐
威哥爱编程1 小时前
Python 智能体开发实战 10:本地跑得好好的,一并发就崩?把它做成一个能上线的服务
python·agent
威哥爱编程1 小时前
Python 智能体开发实战 09:改了提示词,到底是变好还是变坏?搭一套能打分的离线评测
python·agent
wang_yb2 小时前
Pandas 与 Polars:语法、性能和资源占用方面的对比
数据分析·databook
meiying88382 小时前
多快递公司快递单号批量查询接口怎么对接?Python 聚合查询实现
java·大数据·python
Hello_Pyhx2 小时前
Deep-Live-Cam 源码配置思路:环境、模型与执行后端分开排查
python
张张123y3 小时前
后端第十六课:Multi-Agent 多智能体(让多个 Agent 分工协作)
大数据·数据库·人工智能·python·deepseek·dsh·agent 框架
全栈练习生3 小时前
大规模智能体仿真
python·ai
code2cat3 小时前
【随笔】vLLM前缀缓存:相同的开头怎样少算一次
人工智能·python·缓存·vllm
陈飞EXCEL3 小时前
北京杰飞 IT 旗下妙码生花少儿Python编程上线两大学习系统
开发语言·python·学习