一份240M行的点击流数据,18个Parquet文件,14GB磁盘占用。同样的聚合、连接、过滤任务,Polars跑完只花了Pandas十分之一的时间。这不是厂商宣传,是inDrive工程负责人Maksim Danilchenko在2026年初花两个月跑出来的生产级基准。今天把这份账本摊开,讲清Python数据分析选型到底该怎么定。
先看数据:10倍差距是真的
测试硬件是一台M2 Pro,16核32GB内存,每个操作跑5次取中位数。版本为Pandas 2.2对Polars 1.18。
| 操作 | Pandas 2.2 | Polars (lazy) | 加速比 |
| — | — | — | — |
| 读取14GB Parquet | 41.2 s | 8.7 s | 4.7× |
| 单条件过滤 | 3.8 s | 0.34 s | 11× |
| 分组聚合(4个指标) | 18.4 s | 1.8 s | 10× |
| 内连接(5M × 240M) | 22.6 s | 2.1 s | 10.7× |
| 双列排序 | 14.1 s | 1.3 s | 10.8× |
| 窗口函数 | 11.7 s | 1.1 s | 10.6× |
| 写Parquet | 24.8 s | 6.4 s | 3.9× |
这组数字里藏着两个信号。第一,lazy模式一定要开。急切执行模式的Polars已经很快,查询优化器还能再省30-60%时间,原理是重排过滤顺序、把谓词下推到Parquet读取器、跳过无用列。第二,字符串操作差距小。表里唯一不悬殊的一行是字符串包含加过滤,只有1.3倍。如果你的管道八成时间在跑正则解析,提速神话就打了折扣。
Pandas 3.0出了三张新牌
2026年1月21日,Pandas 3.0正式发布,这是1.0以来最大的一次升级。三个默认行为直接改动,力度不小。
字符串成为真正的dtype。 以前pd.Series装字符串得到object类型,3.0会推断出独立的str dtype,背后由PyArrow支撑。.str.contains()和.str.lower()比老的object路径快好几倍,文本列内存占用砍掉一半。Pandas唯一占优的那行基准,优势还会扩大。
写时复制成为默认。 SettingWithCopyWarning没了,切片到底是视图还是副本不再需要猜。链式赋值df[df.a > 0][“b”] = 1会静默失败,从警告改成彻底停摆。老代码库升级3.0要留足预算,失败不报错这件事最伤。
pd.col()表达式API。 df.assign(c=pd.col(“a”) + pd.col(“b”))这种写法,读起来和Polars几乎一样。它比Polars窄:没有惰性执行计划,没有查询优化器,不能跨DataFrame复用。如果你的数据量一直装得进内存,切换理由被砍掉一大块。
问题在于引擎没动。Pandas 3.0依旧单线程、依旧只有急切执行。上表那10倍差距,来源是Polars的多核并行加lazy查询优化器,而PyArrow字符串、写时复制、pd.col()一个都碰不到这些。中等数据量下切换的理由确实变小了,大数据量下一切照旧。
各自的地盘
Polars赢在引擎,Pandas赢在生态。这局棋没有单一答案。
Polars的地盘: 超过5GB的数据集、需要流式或惰性求值的生产ETL、对延迟敏感的任务、新项目。多核是默认行为,Rust内核加Apache Arrow列式内存,数据比内存大时用collect(engine=”streaming”)直接流式处理,不用请Dask或DuckDB出场。
Pandas的地盘: 交互式小数据分析、依赖scikit-learn的机器学习管道、团队已经熟悉的存量代码。15年的库惯性摆在那,每个Python数据教程、每个ML库、每个BI工具都在说它的语言。大多数scikit-learn估计器仍然只认NumPy数组或Pandas DataFrame,Polars要走.to_pandas()或.to_numpy()做交接,数值列靠Arrow后端做到零拷贝。
Pandas会在2026年被Polars取代吗?不会。现实结局是共存:需要速度的地方上Polars,周边库在哪就留在哪。这个格局至少再撑两年。
两边代码长什么样
读CSV、按日期窗口过滤、按用户和事件类型分组求均值、排序输出。同一个任务,两种写法。
“`python
df = pd.read_csv(“events.csv”, parse_dates=[“ts”])
out = (df[df[“ts”].between(“2026-08-01”, “2026-08-31”)]
.groupby([“user_id”, “event”])
.agg(m=(“value”, “mean”))
.reset_index()
.sort_values(“m”, ascending=False))
out = (pl.scan_csv(“events.csv”)
.filter(pl.col(“ts”).is_between(
date(2026, 8, 1), date(2026, 8, 31)))
.group_by([“user_id”, “event”])
.agg(m=pl.col(“value”).mean())
.sort(“m”, descending=True)
.collect())
“`
Pandas靠.loc、.iloc加方法链,Polars全程表达式。API迁移成本真实存在,别指望API是即插即用,把它当成学一门姊妹语言更靠谱。
迁移前问自己三个问题
数据多大? 1GB以下,两个库的差距你根本感知不到,留Pandas。5GB以上,Polars开始明显赢。中间地带看任务类型,正则重的留Pandas,聚合连接重的上Polars。
周边生态绑多深? scikit-learn、matplotlib、plotly都需要.to_pandas()做中转。管道每多一次转换,收益就打一次折。新管道没有历史包袱,直接Polars起步。
每天在烧多少机器时间? 那条没人喜欢又跑得很慢的日终任务,正是第一个该动的候选。作者移植了两条生产管道后的做法是两个都用:批量转换走Polars,最后一公里交给Pandas。
底线
Polars是2026年新建数据管道的正确默认选项,几GB以上的生产ETL也值得认真考虑。10倍加速真实存在,而且在生产环境真正会跑的那些操作上经久耐用。迁移成本同样真实,不能一笔带过。
手里跑得好好的Pandas管道,别动。新写的项目,从Polars开始。处在中间状态的慢任务,移植它,把时间省下来。别忘了DuckDB Labs维护的db-benchmark还在持续更新,0.5GB、5GB、50GB三个档位的横评数据随时可查,选型前先去对一遍账。
相关话题可以接着看uv对pip对Poetry的包管理之争,Python 3.14的free-threading基准测试。Polars加free-threading的组合效果比预期更好,值得单独开一篇。
苏公网安备32010502011527号
发表回复