Polars 性能碾压 Pandas 吗?千万级真实业务数据实测给出答案

简介: Polars 性能碾压 Pandas 吗?千万级真实业务数据实测给出答案

围绕 Polars 最常见的说法是"比 Pandas 快 10~30 倍"。这个数字在官方 benchmark 和社区博客里反复出现,但对于一线业务开发者,真正需要回答的问题有三个:在我自己的数据规模上到底快多少?优势集中在哪些操作?迁移的工程代价值不值?
本文用一份千万行真实业务数据,在严格控制变量的条件下实测载入、过滤、分组聚合、Join、排序五大核心操作,并给出迁移决策框架。
一、两位选手的架构差异
性能差距的根源不在代码层面,而在底层架构选型。
维度
Pandas 2.2
Polars 0.20
底层实现
C + Cython
Rust
执行模型
单线程(GIL 限制)
多线程并行(Rayon 调度器)
内存格式
NumPy ndarray
Apache Arrow(列式、零拷贝)
执行模式
Eager(立即执行)
Eager + Lazy(惰性查询优化)
Lazy 优化能力

谓词下推、投影裁剪、并行哈希
三句话概括差异:Pandas 的每一步操作是单线程立即执行,Polars 是多线程并行执行;Pandas 读完 CSV 还要做一次内存格式转换,Polars 基于 Arrow 零拷贝直接可用;Polars 的 Lazy API 能在执行前看到完整查询计划,做全局优化。这些架构差异决定了后面的实测数字。
二、测试环境与数据
```硬件: 8 核 16G 服务器
Python: 3.12.1
Pandas: 2.2.0
Polars: 0.20.15
数据量: 1000 万行 × 12 列(CSV 文件 567 MB)


数据生成
```import pandas as pd
import numpy as np
import polars as pl
import time

np.random.seed(42)
N = 10_000_000

df_source = pd.DataFrame({
    'order_id':   range(N),
    'user_id':    np.random.randint(1, 500_000, N),
    'product_id': np.random.randint(1, 10_000, N),
    'amount':     np.random.uniform(10, 5000, N).round(2),
    'quantity':   np.random.randint(1, 50, N),
    'region':     np.random.choice(['华东', '华南', '华北', '西南', '东北'], N),
    'category':   np.random.choice(['电子', '服装', '食品', '家居', '图书'], N),
    'status':     np.random.choice(['paid', 'pending', 'refunded', 'shipped'], N),
    'channel':    np.random.choice(['app', 'web', 'mini_program'], N),
    'order_date': pd.date_range('2023-01-01', periods=N, freq='s'),
})

df_source.to_csv('orders_10m.csv', index=False)

计时工具
```def benchmark(func, args, repeat=3, **kwargs):
"""执行多次取最优值,减少系统调度波动"""
times = []
for _ in range(repeat):
start = time.perf_counter()
result = func(
args, **kwargs)
times.append(time.perf_counter() - start)
return min(times), result


三、五大核心操作实测
3.1 CSV 载入
```# Pandas
def pandas_read():
    return pd.read_csv('orders_10m.csv',
        dtype={'region': 'category', 'category': 'category', 'status': 'category'},
        parse_dates=['order_date'])

# Polars(默认多线程解析)
def polars_read():
    return pl.read_csv('orders_10m.csv',
        schema_overrides={'order_date': pl.Datetime},
        try_parse_dates=True)

p_time, _ = benchmark(pandas_read)
pl_time, _ = benchmark(polars_read)
print(f"Pandas: {p_time:.2f}s | Polars: {pl_time:.2f}s | 加速比: {p_time/pl_time:.1f}x")

实测结果:

耗时
内存峰值
Pandas
12.40s
1.8 GB
Polars
2.10s
0.9 GB
差距的原因是双重的:Polars 用多线程并行解析 CSV 文件(8 核同时读取不同 chunk),且基于 Arrow 列式格式,解析完成后无需从 NumPy 数组做内存转换。Pandas 单线程读取完后,还要将 object 列逐个转换为 category,额外消耗了 6~8 秒。
3.2 数据过滤
```# Pandas:筛选金额 >1000 且华东地区的已付款订单
def pandas_filter(df):
return df[(df['amount'] > 1000) & (df['region'] == '华东') & (df['status'] == 'paid')]

Polars Eager

def polars_filter(df):
return df.filter(
(pl.col('amount') > 1000) &
(pl.col('region') == '华东') &
(pl.col('status') == 'paid'))

Polars Lazy(惰性执行,可优化查询计划)

def polars_lazy_filter(lf):
return lf.filter(
(pl.col('amount') > 1000) &
(pl.col('region') == '华东') &
(pl.col('status') == 'paid')).collect()


实测结果:
方案
耗时
Pandas
0.38s
Polars Eager
0.09s
Polars Lazy
0.07s
过滤是纯 CPU 操作,将千万行数据均分到 8 个线程并行扫描,Pandas 单线程遍历需要 0.38 秒,Polars 8 核并行降到 0.09 秒。Lazy 模式还能在执行前发现可以提前裁剪的列(这里只需 amount、region、status 三列),减少内存读取量,再快 20%。
3.3 分组聚合
```# Pandas
def pandas_groupby(df):
    return df.groupby(['region', 'category']).agg(
        total_amount=('amount', 'sum'),
        avg_amount=('amount', 'mean'),
        max_amount=('amount', 'max'),
        order_count=('order_id', 'count'),
        unique_users=('user_id', 'nunique'),
    ).reset_index()

# Polars
def polars_groupby(df):
    return df.group_by(['region', 'category']).agg([
        pl.col('amount').sum().alias('total_amount'),
        pl.col('amount').mean().alias('avg_amount'),
        pl.col('amount').max().alias('max_amount'),
        pl.col('order_id').count().alias('order_count'),
        pl.col('user_id').n_unique().alias('unique_users'),
    ])

这是日常分析中最频繁、也最耗时的操作。
实测结果:
方案
耗时
Pandas
1.42s
Polars Eager
0.31s
Polars Lazy
0.22s
分组聚合是 Polars 优势最突出的场景。Pandas 单线程遍历千万行做 hash 分桶,耗时 1.4 秒。Polars 使用并行哈希聚合算法——将数据按 hash 分片到 8 个线程,每个线程独立构建局部哈希表,最后合并结果。Lazy 模式还能合并多个聚合操作到单次遍历中。
3.4 Join 合并
```# 右表:产品维度表 1 万行
products = pd.DataFrame({
'product_id': range(1, 10_001),
'productname': [f'商品{i}' for i in range(1, 10_001)],
'brand': np.random.choice(['品牌A', '品牌B', '品牌C'], 10000),
})
products.to_csv('products.csv', index=False)

Pandas

def pandas_join(orders, products):
return pd.merge(orders, products, on='product_id', how='left')

Polars

def polars_join(orders_pl, products_pl):
return orders_pl.join(products_pl, on='product_id', how='left')


实测结果:
方案
耗时
Pandas
3.85s
Polars
0.52s
Join 是 Pandas 的传统痛点。pd.merge 在千万级数据上做哈希连接时,单线程构建哈希表 + 单线程探测匹配,耗时接近 4 秒。Polars 使用并行哈希连接——将左表按 product_id 的 hash 值分片,每个线程处理一片,与右表的哈希表做局部匹配后合并。
3.5 排序
```# Pandas
def pandas_sort(df):
    return df.sort_values(['region', 'amount'], ascending=[True, False])

# Polars
def polars_sort(df):
    return df.sort(['region', 'amount'], descending=[False, True])

实测结果:
方案
耗时
Pandas
4.67s
Polars
0.85s
排序是千万行数据上的性能重灾区。Pandas 依赖 NumPy 的单线程快速排序,在多列排序场景下需要多次分区遍历。Polars 使用并行归并排序——将数据分片排序后多路归并。
四、汇总:全景性能对比
操作
Pandas
Polars Eager
Polars Lazy
加速比
CSV 载入
12.40s
2.10s

5.9x
过滤
0.38s
0.09s
0.07s
5.4x
分组聚合
1.42s
0.31s
0.22s
6.5x
Join 合并
3.85s
0.52s

7.4x
排序
4.67s
0.85s

5.5x
全链路
22.72s
3.87s

5.9x
核心结论:千万级数据规模下,Polars 在所有核心操作上均有 5~7 倍的加速。优势集中在三类操作——Join(并行哈希)、分组聚合(并行哈希分桶)、排序(并行归并)。数据量越大,并行收益越显著。
五、公平修正:Pandas + PyArrow 后端
Pandas 2.0 引入了 PyArrow 后端,部分缩小了差距。补上这组数据:
操作
Pandas 原生
Pandas + PyArrow
Polars
CSV 载入
12.40s
3.21s
2.10s
分组聚合
1.42s
0.89s
0.31s
Join 合并
3.85s
1.95s
0.52s
PyArrow 后端让 Pandas 在 CSV 载入上追近 Polars(差距从 6 倍缩小到 1.5 倍),但在分组聚合和 Join 上仍有 3~4 倍差距。单线程架构的计算瓶颈无法被内存格式优化弥补。
六、迁移成本评估
性能数字只是决策的一个维度。迁移到 Polars 意味着 API 重写和生态适配。
6.1 API 差异核心对照
操作
Pandas
Polars
新增列
df['c'] = df['a'] + df['b']
df.with_columns((pl.col('a') + pl.col('b')).alias('c'))
条件赋值
np.where(df['a']>0, 'Y', 'N')
pl.when(pl.col('a')>0).then('Y').otherwise('N')
分组聚合
df.groupby('a').agg({'b':'sum'})
df.group_by('a').agg(pl.col('b').sum())
Merge
pd.merge(df1, df2, on='key')
df1.join(df2, on='key')
链式空值填充
df['a'].fillna(0)
df.with_columns(pl.col('a').fill_null(0))
6.2 迁移决策矩阵
条件
建议
数据量 < 100 万行
Pandas 够用,迁移收益有限
数据量 100 万~1000 万行
推荐迁移,单操作快 3~5 倍
数据量 > 1000 万行
必须迁移,Pandas 已无法胜任
Join / GroupBy 是主要瓶颈
优先迁移这两类操作
重度依赖 scikit-learn / statsmodels
渐进迁移,分析阶段用 Polars,ML 阶段 to_pandas()
转换
存量 Pandas 代码 > 5000 行
新模块用 Polars,旧模块按需重构
6.3 渐进迁移策略
to_pandas() 在底层使用 Arrow 零拷贝机制,转换耗时在毫秒级,不构成性能瓶颈。
七、完整数据链路的性能优化
在企业场景中,性能瓶颈不仅在分析阶段,也在数据采集阶段。原始数据通过 API 或爬虫从外部获取时,采集效率直接影响分析的时效性。
```import requests
import polars as pl
from io import StringIO

通过亿牛云 API 代理获取出口 IP,避免单 IP 被限流

api_url = "http://ip.16yun.cn:817/myip/pl//?s=&u=&format=json"
proxy_info = requests.get(api_url, timeout=10).json()[0]
proxy = f"http://{proxy_info['ip']}:{proxy_info['port']}"

采集数据(返回 403 检查白名单,返回 429 降低频率)

resp = requests.get("https://api.example.com/export",
proxies={"http": proxy, "https": proxy}, timeout=30)

直接从内存字符串载入 Polars,跳过文件落盘

df = pl.read_csv(StringIO(resp.text), try_parse_dates=True)

Polars Lazy 链式分析

result = (df.lazy()
.filter(pl.col('amount') > 100)
.group_by('region')
.agg(pl.col('amount').sum().alias('revenue'))
.collect()
)
```

这条链路的优化点是:代理 IP 保证采集不被限流,read_csv(StringIO) 省去文件 I/O,Polars Lazy 引擎在 collect() 时才触发执行并做全局优化。相比"采集 → 存 CSV → Pandas 读取 → 分析"的传统链路,整体耗时减少 60% 以上。
八、最终判断
基于实测数据,迁移决策可以拆成三个层次:
第一层:看数据规模
数据量
推荐方案
< 10 万行
Pandas,迁移无意义
10 万~500 万行
Pandas + PyArrow 后端
500 万~5000 万行
Polars(单机最优解)

5000 万行
Polars Lazy + DuckDB
第二层:看瓶颈操作
如果业务中高频使用 Join 和 GroupBy,迁移收益最大——这两个操作 Polars 快 6~7 倍。如果主要是列选择和简单过滤,差距不到 3 倍,迁移必要性不大。
第三层:看生态依赖
重度依赖 scikit-learn、statsmodels、Matplotlib 的项目,最终仍需转回 Pandas。但 to_pandas() 的零拷贝转换耗时在毫秒级,不构成实质障碍。
"Polars 碾压 Pandas"这个说法在千万级数据 + 计算密集型操作的条件下成立,在十万级数据 + 简单过滤的场景下不成立。选型的正确姿势是:先用你的真实数据跑一遍 benchmark,再基于实测数字做决策,而不是被社区营销数字牵着走。

相关文章
|
7月前
|
数据采集 JSON Java
Java 异步爬虫高效获取小红书短视频内容
Java 异步爬虫高效获取小红书短视频内容
|
8月前
|
数据采集 文字识别 JavaScript
基于文本检测的 Python 爬虫弹窗图片定位与拖动实现
基于文本检测的 Python 爬虫弹窗图片定位与拖动实现
|
4月前
|
存储 API 数据安全/隐私保护
Python 自动化爬取网易云音乐歌手歌词实战教程
Python 自动化爬取网易云音乐歌手歌词实战教程
|
9月前
|
数据采集 自然语言处理 数据可视化
时序数据分析:Python爬取新浪财经频道新闻并绘制趋势图
时序数据分析:Python爬取新浪财经频道新闻并绘制趋势图
|
3月前
|
数据采集 数据可视化 数据挖掘
均线选股策略研究:基于 Python 数据分析实现
均线选股策略研究:基于 Python 数据分析实现
|
3月前
|
数据采集 Web App开发 JavaScript
Python 爬虫动态 JS 渲染与无头浏览器实战选型指南
Python 爬虫动态 JS 渲染与无头浏览器实战选型指南
|
3月前
|
数据采集 JSON 数据安全/隐私保护
Python 爬虫爬取应用商店数据:请求构造与数据解析
Python 爬虫爬取应用商店数据:请求构造与数据解析
|
3月前
|
数据采集 Web App开发 JSON
基于大模型的Python智能爬虫:语义识别与数据清洗实践
基于大模型的Python智能爬虫:语义识别与数据清洗实践
|
3月前
|
数据采集 JSON 数据挖掘
抖音搜索页数据批量爬取,多关键词同步采集实现
抖音搜索页数据批量爬取,多关键词同步采集实现
|
4月前
|
数据采集 Web App开发 开发者
解决 Python 爬虫被限制:延迟抓取指令深度解析
解决 Python 爬虫被限制:延迟抓取指令深度解析

热门文章

最新文章