数据处理库 Pandas 和 Polars 读写速度对比如何

文章导读
数据量超过 500 万行或文件大于 1GB 时,Polars 在读写速度上通常明显优于 Pandas;小数据量场景下两者差距不大,Pandas 的生态优势更值得保留。
📋 目录
  1. 测试环境与版本说明
  2. 可复现的性能测试脚本
  3. 核心差异解析
  4. 迁移实操步骤
  5. 效果验证方法
  6. 常见坑与排查
  7. 参考来源
A A

数据量超过 500 万行或文件大于 1GB 时,Polars 在读写速度上通常明显优于 Pandas;小数据量场景下两者差距不大,Pandas 的生态优势更值得保留。

先说结论:Polars 在大数据集读写场景下性能优势显著,但迁移成本和学习曲线需要考虑,不建议盲目替换现有 Pandas 代码。

  • 适合:单次操作超过 500 万行、CPU 长期单核满载、读取超过 1GB 的 CSV/Parquet 文件
  • 重点看:分组聚合、链式过滤、流式处理超内存数据这三类操作的性能收益
  • 别忽略:小数据量场景下 Pandas 的语法直觉和机器学习生态优势仍然明显

测试环境与版本说明

性能测试结果高度依赖硬件配置和库版本,以下建议基于主流工程环境:

  • Python 版本:建议 3.9 及以上
  • Pandas 版本:2.0+ (性能有所优化)
  • Polars 版本:0.19+ (API 相对稳定,支持 thread_pool_size)
  • 硬件建议:Polars 的多核优势在 4 vCPU 以上环境更明显,建议使用 SSD 以减少 I/O 瓶颈
  • 安装命令:pip install pandas polars pyarrow

可复现的性能测试脚本

如果你正在评估是否迁移,先用以下完整代码快速测试自己场景的实际收益。注意替换文件路径并确保环境一致:

import pandas as pd
import polars as pl
import time
import os

file_path = 'your_file.parquet'

# 检查文件是否存在
if not os.path.exists(file_path):
    print(f'文件 {file_path} 不存在,请替换为真实路径')
    exit()

# 测试 Pandas 读取速度
start = time.time()
df_pd = pd.read_parquet(file_path)
pandas_time = time.time() - start
print(f'Pandas 读取耗时:{pandas_time:.2f}秒')

# 测试 Polars 读取速度
start = time.time()
df_pl = pl.read_parquet(file_path)
polars_time = time.time() - start
print(f'Polars 读取耗时:{polars_time:.2f}秒')

# 检查 Polars 线程数是否匹配实际 vCPU
# 注意:API 随版本变化,0.19+ 使用 thread_pool_size
try:
    print(f'当前线程池大小:{pl.thread_pool_size()}')
except AttributeError:
    print('当前 Polars 版本不支持 thread_pool_size 查询,请查阅对应版本文档')

print(f'性能提升倍数:{pandas_time / polars_time:.2f}x' if polars_time > 0 else 'Polars 耗时过短')

核心差异解析

两者速度差异主要来自三个底层设计不同:

1. 语言和执行模式

Pandas 基于 Python+NumPy,受 GIL 锁限制,默认单线程执行。Polars 用 Rust 编写,支持多核并行,CPU 利用率可以跑满多个核心。

2. 内存存储结构

Pandas 采用行式存储,读取一列数据需要加载整行。Polars 基于 Apache Arrow 列式存储,只加载需要的列,内存占用更低,I/O 开销更小。

3. 求值策略

Pandas 每行代码立即执行,中间结果会生成新 DataFrame。Polars 支持惰性求值,先构建执行计划,自动优化操作序列后再执行,减少不必要的计算和内存拷贝。

数据处理库 Pandas 和 Polars 读写速度对比如何

迁移实操步骤

第一步:确认你的数据规模

用以下代码快速检查当前数据量,避免盲目迁移:

import pandas as pd

# 仅读取前 1000 行进行估算,避免大文件加载过慢
df = pd.read_csv('your_file.csv', nrows=1000)
# 基于采样推算总行数,实际值可能有偏差
estimated_rows = len(df) * 1000
print(f'预估总行数:{estimated_rows} (基于前 1000 行推算)')
print(f'列数:{len(df.columns)}')

如果行数超过 500 万或文件超过 1GB,可以考虑测试 Polars。

第二步:小范围迁移测试

不要一次性替换全部代码,先选一个读取或聚合操作做对比:

# Pandas 原代码
df = pd.read_csv('data.csv')
result = df[df['value'] > 100].groupby('category').sum()

# Polars 等价代码
import polars as pl
df = pl.read_csv('data.csv')
# 注意:group_by 后必须显式调用 agg()
result = df.filter(pl.col('value') > 100).group_by('category').agg(pl.all().sum())

第三步:调整线程配置

Polars 默认启用所有逻辑核心,但在虚拟机或容器中可能被限制。如果运行在 vCPU 受限的环境,需要显式设置:

import polars as pl
# Polars 0.19+ 推荐配置方式
pl.Config.set_thread_pool_size(2)  # 设为实际可用的 vCPU 数

效果验证方法

1. 时间对比

用 time 模块或%timeit 记录相同操作在两个库下的耗时,差距在 3 倍以上才有迁移价值。

2. 内存监控

使用系统监控工具观察内存占用,Polars 在处理大文件时内存占用通常为 Pandas 的 1/5 到 1/10。

数据处理库 Pandas 和 Polars 读写速度对比如何

3. CPU 利用率

运行期间观察 CPU 使用率,Polars 应该能看到多核同时工作,而 Pandas 通常只有一个核心满载。

常见坑与排查

1. API 不完全兼容

Polars 的 API 与 Pandas 高度相似但有差异,例如布尔索引语法不支持、fillna 改为 fill_null、groupby 后必须显式调用 agg() 等,直接复制代码会报错。

2. 惰性求值需要主动启用

使用 pl.read_csv() 是立即执行,想利用惰性优化需要用 pl.scan_csv() + .collect(),否则性能优势会打折扣。

3. 小数据量反而更慢

Polars 有编译和初始化开销,100 万行以下的数据集两者耗时差在秒级,Pandas 的语法直觉和生态优势更明显。

4. 机器学习生态支持

scikit-learn、matplotlib、seaborn 等库原生支持 Pandas DataFrame,使用 Polars 可能需要额外转换步骤(如 .to_pandas())。

参考来源

  • Polars 与 Pandas 核心架构差异对比 - 官方文档关于底层实现、执行模式、内存模型的说明
  • 2024 年公开基准测试数据 - 社区关于大尺寸数据集下性能对比的汇总
  • Polars 官方基准测试 - TPC-H 基准测试中 Polars 表现优于 Pandas 的相关数据(多核环境)
  • Polars 文档 - 关于 Config.set_thread_pool_size 线程配置和惰性求值的使用说明