Polars:超越 Pandas,下一代高性能数据分析框架
Polars:超越 Pandas,下一代高性能数据分析框架
在 Python 数据科学领域,Pandas 长期以来是无可争议的王者。然而,随着数据集的日益庞大和多核 CPU 的普及,Pandas 在性能和内存效率上的瓶颈也愈发凸显。Polars,一个从零开始用 Rust 编写的高性能 DataFrame 库,正以其闪电般的速度和富有表现力的 API,成为数据分析领域的下一代挑战者。本文将通过 7 个实战案例,带你领略 Polars 的魅力。

导语
为什么我们需要 Pandas 的替代品?
- 单线程限制:Pandas 的大部分操作是单线程的,无法充分利用现代 CPU 的多核优势。
- 内存开销:Pandas 的内存使用效率不高,尤其是在处理大量字符串或进行某些操作(如
copy)时。 - API 不一致:Pandas 的 API 历史悠久,存在一些不一致和令人困惑的地方。
- 渴望性能:数据科学家和工程师们花费了大量时间等待 Pandas 完成计算,这直接影响了迭代速度。
Polars 正是为解决这些痛点而生。它基于 Apache Arrow 列存格式,并利用 Rust 的能力实现了大规模的并行计算和查询优化。其核心设计理念是:
- 最大化并行计算:自动利用所有可用的 CPU 核心。
- 查询优化:通过惰性求值(Lazy Evaluation)分析整个查询计划,寻找最优执行路径。
- 富有表现力的 API:提供一种链式、声明式的“表达式” API,代码更易读、更稳定。
一、环境准备与核心思想
首先,安装 Polars。
pip install polars
(可选)为了更好地支持 CSV 读取和与其他库的交互,可以安装更多依赖:
pip install polars[all]
核心思想:表达式 (Expressions)
Polars 的核心是表达式 API。与 Pandas 中 df['A'] * 2 这样立即执行的操作不同,Polars 的 pl.col('A') * 2 创建了一个描述“如何计算”的表达式对象。这些表达式可以被组合、传递,并由 Polars 的查询引擎在后台进行优化和并行执行。
二、案例一:拥抱表达式 API
让我们从基础的读数据、选择和创建新列开始,感受 Polars 表达式的魅力。
import polars as pl
# 创建一个 DataFrame
data = {
"city": ["New York", "London", "Tokyo", "Paris", "London"],
"country": ["USA", "UK", "Japan", "France", "UK"],
"temperature_c": [22.5, 15.0, 28.3, 25.1, 18.5],
"humidity": [65, 72, 75, 68, 70],
}
df = pl.DataFrame(data)
# 1. 选择列 (select)
# Pandas: df[['city', 'temperature_c']]
selected_df = df.select([
pl.col("city"),
pl.col("temperature_c")
])
print("--- Selected DataFrame ---\n", selected_df)
# 2. 创建新列 (with_columns)
# Pandas: df['temperature_f'] = df['temperature_c'] * 9/5 + 32
transformed_df = df.with_columns([
# 使用表达式创建新列
(pl.col("temperature_c") * 9/5 + 32).alias("temperature_f"),
# 对字符串列进行操作
pl.col("city").str.to_uppercase().alias("city_uppercase")
])
print("\n--- Transformed DataFrame ---\n", transformed_df)
结果分析:
- 我们不再使用
df['col']的方式,而是用pl.col("col")创建一个代表列的表达式。 - 所有操作都封装在
select或with_columns的上下文中,这让 Polars 可以整体看待这些操作。 .alias("new_name")用于给新创建的表达式(列)命名,清晰直观。
三、案例二:链式操作与高效过滤
Polars 的 API 设计非常适合链式调用,使得复杂的数据处理流程一目了然。
import polars as pl
df = pl.DataFrame({
"type": ["A", "B", "A", "C", "B", "A"],
"value": [10, 20, 30, 40, 50, 60]
})
# 需求:筛选出 type 为 'A' 的行,并将 value 乘以 2
# Pandas: df[df['type'] == 'A']['value'] * 2
# Polars 写法
result = (
df.filter(pl.col("type") == "A")
.select(
(pl.col("value") * 2).alias("doubled_value")
)
)
print(result)
结果分析:通过 filter 和 select 的链式调用,代码从上到下清晰地描述了数据处理的每一步。这种声明式的风格比 Pandas 中混合使用 [] 和方法调用更容易阅读和维护。
四、案例三:闪电般的分组聚合 (group_by)
group_by 是数据分析的核心操作。Polars 的 group_by 利用了多核能力,执行速度远超 Pandas。
import polars as pl
import numpy as np
# 创建一个更大的 DataFrame
num_rows = 1_000_000
data = {
"category": np.random.choice(["A", "B", "C", "D"], num_rows),
"value1": np.random.rand(num_rows) * 100,
"value2": np.random.rand(num_rows) * 50,
}
df = pl.DataFrame(data)
# 需求:按 category 分组,计算每个组的
# 1. 行数 (count)
# 2. value1 的总和 (sum)
# 3. value2 的平均值 (mean)
# 4. value1 的中位数 (median)
aggregated_df = df.group_by("category").agg([
pl.count().alias("num_rows"),
pl.sum("value1").alias("sum_value1"),
pl.mean("value2").alias("mean_value2"),
pl.median("value1").alias("median_value1"),
# 还可以对一列应用多个聚合
pl.col("value1").filter(pl.col("value1") > 50).count().alias("count_value1_gt_50")
]).sort("category")
print(aggregated_df)
结果分析:group_by().agg() 的语法非常强大。你可以在 agg 中传入一个表达式列表,对不同的列执行不同的聚合操作,甚至可以包含过滤条件。这一切都会被 Polars 的查询引擎优化并并行执行。
五、案例四:使用 Lazy API 优化查询
Lazy API 是 Polars 的性能“核武器”。它允许你先构建查询计划,然后让 Polars 对整个计划进行优化(如谓词下推、投影下推),最后再执行计算。
import polars as pl
df = pl.DataFrame({
"type": ["A", "B", "A", "C", "B", "A"],
"value": [10, 20, 30, 40, 50, 60]
})
# 创建一个 LazyFrame
lazy_df = df.lazy()
# 构建查询计划 (此时不进行任何计算)
query_plan = (
lazy_df.filter(pl.col("value") > 25)
.with_columns(
(pl.col("value") * 10).alias("value_x10")
)
.select(["type", "value_x10"])
)
# 查看优化后的查询计划
print("--- Optimized Execution Plan ---")
print(query_plan.describe_optimized_plan())
# 触发计算并获取结果
print("\n--- Result ---")
result_df = query_plan.collect()
print(result_df)
结果分析:
.lazy()将 DataFrame 转换为 LazyFrame,后续所有操作都只构建查询计划。describe_optimized_plan()可以让你看到 Polars 打算如何执行你的查询。你会发现,它会先执行过滤(filter),再进行计算(with_columns),从而减少需要处理的数据量——这就是谓词下推优化。.collect()触发实际的计算。对于大型数据集,特别是从文件中读取时,Lazy API 可以通过避免读取不必要的列和行,极大地提升性能和降低内存消耗。
六、案例五:强大的窗口函数 (over)
窗口函数允许你在一个“窗口”(一组相关的行)内进行计算,而无需像 group_by 那样将行折叠。
import polars as pl
df = pl.DataFrame({
"department": ["Sales", "Sales", "Marketing", "Engineering", "Marketing"],
"employee": ["Alice", "Bob", "Charlie", "David", "Eve"],
"salary": [80000, 90000, 75000, 120000, 85000],
})
# 需求:计算每个员工的薪水与他/她所在部门平均薪水的差异
result_df = df.with_columns([
(pl.col("salary") - pl.mean("salary").over("department")).alias("salary_diff_from_dept_avg")
])
print(result_df)
结果分析:pl.mean("salary").over("department") 这一行代码的含义是:“计算按 department 分组的 salary 的平均值,但不要折叠行,而是将结果广播回每一行”。这使得计算组内相对值变得异常简单和高效,其可读性远超 Pandas 中使用 transform 的等效操作。
七、案例六:高效连接数据 (join)
join 是合并数据的基本操作,Polars 同样提供了高效的实现。
import polars as pl
df_users = pl.DataFrame({
"user_id": [1, 2, 3],
"name": ["Alice", "Bob", "Charlie"]
})
df_orders = pl.DataFrame({
"order_id": [101, 102, 103],
"user_id": [2, 3, 1],
"amount": [150, 200, 100]
})
# 执行内连接
joined_df = df_users.join(df_orders, on="user_id", how="inner").sort("user_id")
print(joined_df)
结果分析:join 的语法清晰明了,支持 inner, left, outer, semi, anti 等多种连接策略。由于其并行的哈希连接算法,在大数据集上的性能同样出色。
八、案例七:与 Pandas/NumPy 无缝切换
Polars 并非要完全孤立于现有的 PyData 生态。得益于 Apache Arrow,它可以与 Pandas 和 NumPy 进行零成本(zero-copy)或低成本的数据交换。
import polars as pl
import pandas as pd
import numpy as np
# Polars -> Pandas
pl_df = pl.DataFrame({"a": [1, 2], "b": [3, 4]})
pd_df = pl_df.to_pandas()
print("--- Converted to Pandas ---\n", pd_df)
print(type(pd_df))
# Pandas -> Polars
pl_df_from_pd = pl.from_pandas(pd_df)
print("\n--- Converted from Pandas ---\n", pl_df_from_pd)
# Polars -> NumPy
numpy_array = pl_df.to_numpy()
print("\n--- Converted to NumPy ---\n", numpy_array)
print(type(numpy_array))
结果分析:这种无缝转换的能力让你可以在项目的不同阶段选择最合适的工具。例如,你可以用 Polars 完成繁重的数据清洗和预处理,然后将结果转换为 NumPy 数组送入机器学习模型进行训练。
总结与展望
Polars 凭借其基于 Rust 的高性能引擎、富有表现力的表达式 API 和强大的惰性求值能力,为 Python 数据分析领域注入了新的活力。它并非要完全取代 Pandas,而是在性能和处理中大型数据集方面提供了一个更优越的选择。当你还在为 Pandas 的缓慢执行而苦恼时,不妨试试 Polars,它可能会给你带来惊喜。
当你用 Polars 高效地处理和分析完数据,提取出有价值的特征后,下一步便是将这些洞察和特征输入给强大的 AI 模型,去完成更复杂的任务。
从高性能分析到高级智能
- 😳 0v0 AI 助手推荐:对于希望探索如何将数据分析结果与语言模型结合的开发者,
https://0v0.pro是一个理想的试验平台。你可以将 Polars 的分析结论作为上下文,免费、无限制地向 Llama、Qwen、gpt-4o 等多种模型提问,甚至可以体验每周轮换的 gpt-5 等旗舰模型。
Polars 负责“快”,而 AI 负责“聪明”。二者结合,将开启数据应用的新篇章。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)