在使用 Pandas 处理大数据时,你是否也常常被性能问题困扰?一旦数据量超过百万行,筛选、聚合操作就变得异常缓慢,甚至导致程序卡顿。今天,我们将介绍一个高效的大数据处理工具——Polars。它不仅速度远超 Pandas,语法也高度相似,能让新手用更少的代码轻松应对千万级数据。
你可以在 云栈社区 的技术板块找到更多关于数据处理工具的深入讨论和资源分享。
第一步:快速安装与环境准备
Polars 的安装非常简单,只需在命令行中输入以下命令即可:
pip install polars # 基础安装(支持CPU)
# 如果需要处理Excel文件,额外安装:pip install polars[excel]
安装完成后,在代码中导入相关库。习惯上,我们使用 pl 作为 Polars 的别名,类似于 Pandas 的 pd,便于记忆:
import polars as pl
import pandas as pd # 用于和Pandas对比
import time # 测试速度
为了直观感受速度差距,我们用100万行模拟数据,分别对 Pandas 和 Polars 进行相同的筛选与聚合操作,并比较耗时:
# 生成100万行模拟数据(用户ID、年龄、消费金额)
data = {
"user_id": range(1000000),
"age": [pl.randint(18, 60) for _ in range(1000000)],
"amount": [pl.randf(10, 1000) for _ in range(1000000)]
}
# Pandas DataFrame
pd_df = pd.DataFrame(data)
# Polars DataFrame
pl_df = pl.DataFrame(data)
# 测试Pandas:筛选30岁以上用户,按年龄分组计算平均消费
start_pd = time.time()
pd_result = pd_df[pd_df["age"] > 30].groupby("age")["amount"].mean()
end_pd = time.time()
print(f"Pandas 耗时:{end_pd - start_pd:.2f} 秒")
# 测试Polars:同样逻辑
start_pl = time.time()
pl_result = pl_df.filter(pl.col("age") > 30).groupby("age").agg(pl.col("amount").mean())
end_pl = time.time()
print(f"Polars 耗时:{end_pl - start_pl:.2f} 秒")
运行结果(在不同电脑上可能略有差异):
Pandas 耗时:2.86 秒
Polars 耗时:0.08 秒
可以看到,在这个测试中 Polars 足足快了35倍!随着数据量增长到千万行,其性能优势会更加显著,并且整个过程流畅不卡顿。
核心入门:Polars 基础操作(与 Pandas 对比)
Polars 的核心数据结构同样是 DataFrame(表格数据)和 Series(单列数据),其语法设计与 Pandas 非常相似,有助于有基础的用户快速上手。
1. 数据读取(支持多格式,速度更快)
Polars 支持 CSV、Excel、JSON、Parquet 等多种文件格式,其读取速度,尤其是处理大文件时,远超 Pandas。
# 1. 读取CSV(千万级数据秒级读取)
pl_df = pl.read_csv("large_data.csv")
# 2. 读取Excel(需要先安装 polars[excel])
pl_df = pl.read_excel("data.xlsx", sheet_name="Sheet1")
# 3. 和Pandas对比:读取100万行CSV
# Pandas:pd_df = pd.read_csv("large_data.csv") # 耗时约3秒
# Polars:pl_df = pl.read_csv("large_data.csv") # 耗时约0.3秒
2. 数据筛选(语法更简洁)
筛选是数据处理中的高频操作。Polars 使用 filter() 函数,并通过 pl.col(“列名”) 来指定列,条件写法与 Pandas 类似。
# 模拟数据
pl_df = pl.DataFrame({
"name": ["Alice", "Bob", "Charlie", "David", "Ella"],
"age": [25, 32, 28, 45, 36],
"city": ["Beijing", "Shanghai", "Beijing", "Guangzhou", "Shanghai"],
"salary": [8000, 12000, 9500, 15000, 11000]
})
# 示例1:筛选年龄>30的用户
filter1 = pl_df.filter(pl.col("age") > 30)
print("年龄>30的用户:")
print(filter1)
# 示例2:多条件筛选(年龄>30 且 薪资>10000)
filter2 = pl_df.filter((pl.col("age") > 30) & (pl.col("salary") > 10000))
print("\n年龄>30且薪资>10000的用户:")
print(filter2)
# 示例3:筛选城市为北京或上海的用户(isin()函数)
filter3 = pl_df.filter(pl.col(“city”).isin(["Beijing", "Shanghai"]))
print("\n北京/上海的用户:")
print(filter3)
# 和Pandas对比(同样逻辑)
# pd_filter1 = pd_df[pd_df["age"] > 30]
# pd_filter2 = pd_df[(pd_df["age"] > 30) & (pd_df["salary"] > 10000)]
Polars 的筛选语法几乎和 Pandas 一致,只是将 pd_df[“列名”] 替换为 pl.col(“列名”),清晰易懂。
3. 数据聚合(分组统计更高效)
聚合操作(如分组求和、求均值、计数等)是 大数据 处理的核心。Polars 使用 groupby() 进行分组,在 agg() 中指定聚合方式,并支持多列同时聚合。
# 示例1:按城市分组,计算平均薪资和用户数
agg1 = pl_df.groupby(“city”).agg(
pl.col(“salary”).mean().alias(“平均薪资”), # 平均薪资,重命名为“平均薪资”
pl.col(“name”).count().alias(“用户数”) # 用户数,重命名为“用户数”
)
print(“按城市聚合结果:”)
print(agg1)
# 示例2:按年龄区间分组(cut函数),计算薪资总和
# 先创建年龄区间(18-30,31-40,41+)
agg2 = pl_df.with_columns(
pl.col(“age”).cut([18, 30, 40, 100], labels=[“18-30”, “31-40”, “41+”]).alias(“年龄区间”)
).groupby(“年龄区间”).agg(
pl.col(“salary”).sum().alias(“薪资总和”)
)
print(“\n按年龄区间聚合薪资总和:”)
print(agg2)
# 和Pandas对比(同样逻辑)
# pd_agg1 = pd_df.groupby(“city”).agg({
# “salary”: “mean”,
# “name”: “count”
# }).rename(columns={“salary”: “平均薪资”, “name”: “用户数”})
Polars 的聚合语法允许在 agg() 中直接对列进行操作和重命名,代码更加简洁。在处理海量数据时,其速度优势尤为明显。
高效技巧:Polars 的进阶能力
1. 惰性执行:处理超大数据不爆内存
Polars 支持“惰性执行”。你可以先定义一系列操作(如筛选、聚合、排序),Polars 会将其优化为一个执行计划,最后通过 collect() 一次性完成。这种方式能极大节省内存并提升速度,非常适合处理千万行以上的数据集。
# 惰性执行示例:处理1000万行数据
lazy_result = (
pl.scan_csv(“1000w_data.csv”) # 用scan_csv()替代read_csv(),开启惰性模式
.filter(pl.col(“age”) > 25) # 筛选年龄>25
.groupby(“city”) # 按城市分组
.agg(pl.col(“salary”).mean()) # 计算平均薪资
.sort(“salary”, descending=True) # 按薪资降序排序
.collect() # 最后用collect()执行所有操作
)
print(lazy_result)
相比之下,直接用 Pandas 读取和处理千万行数据,很可能会因内存不足而失败。
2. 向量化操作:避免循环,提升性能
与 Pandas 一样,Polars 也支持向量化操作,可以直接对整个数据列进行计算,无需编写低效的 for 循环。
# 给薪资列增加10%(向量化操作)
pl_df = pl_df.with_columns(
(pl.col(“salary”) * 1.1).alias(“涨薪后薪资”)
)
print(“涨薪后的数据:”)
print(pl_df)
# 计算年龄+5(同样向量化)
pl_df = pl_df.with_columns(
(pl.col(“age”) + 5).alias(“5年后年龄”)
)
3. 与 Pandas 无缝转换
如果遇到 Polars 暂不支持的操作,或者你更习惯用 Pandas 处理某些步骤,可以随时在两者之间进行转换。
# Polars DataFrame 转 Pandas DataFrame
pd_df = pl_df.to_pandas()
# Pandas DataFrame 转 Polars DataFrame
pl_df = pl.from_pandas(pd_df)
实战案例:分析百万行电商订单数据
让我们通过一个完整的案例来体验 Polars 的工作流:分析一份100万行的电商订单数据,筛选出高价值订单(金额>500),并按省份统计订单数和总销售额。
# 1. 读取100万行订单数据(CSV格式)
pl_orders = pl.read_csv(“100w_orders.csv”)
print(“数据基本信息:”)
print(pl_orders.head()) # 查看前5行数据
print(f“\n数据总行数:{pl_orders.height}”) # 查看行数(对应Pandas的shape[0])
print(f“数据列名:{pl_orders.columns}”) # 查看列名
# 2. 数据预处理:查看是否有缺失值
print(“\n缺失值统计:”)
print(pl_orders.null_count()) # 统计每列缺失值(对应Pandas的isnull().sum())
# 3. 筛选高价值用户(消费金额amount>500)
high_value_orders = pl_orders.filter(pl.col(“amount”) > 500)
print(f“\n高价值订单数:{high_value_orders.height}”)
# 4. 按省份分组,统计订单数和总销售额
province_stats = high_value_orders.groupby(“province”).agg(
pl.col(“order_id”).count().alias(“订单数”),
pl.col(“amount”).sum().alias(“总销售额”)
).sort(“总销售额”, descending=True) # 按总销售额降序排序
print(“\n各省份高价值用户统计(前10名):”)
print(province_stats.head(10))
运行结果示例:
数据基本信息:
shape: (5, 5)
┌─────────┬──────────┬──────────┬─────────┬────────┐
│ order_id│ user_id │ province │ amount │ date │
│ --- │ --- │ --- │ --- │ --- │
│ i64 │ i64 │ str │ f64 │ str │
╞═════════╪══════════╪══════════╪═════════╪════════╡
│ 1 │ 1001 │ 广东 │ 680.0 │ 2024-01-01 │
│ 2 │ 1002 │ 浙江 │ 320.0 │ 2024-01-01 │
│ 3 │ 1003 │ 广东 │ 890.0 │ 2024-01-01 │
│ 4 │ 1004 │ 江苏 │ 550.0 │ 2024-01-01 │
│ 5 │ 1005 │ 广东 │ 720.0 │ 2024-01-01 │
└─────────┴──────────┴──────────┴─────────┴────────┘
数据总行数:1000000
数据列名:[‘order_id’, ‘user_id’, ‘province’, ‘amount’, ‘date’]
缺失值统计:
shape: (5,)
┌─────────┬──────────┬──────────┬─────────┬────────┐
│ order_id│ user_id │ province │ amount │ date │
│ --- │ --- │ --- │ --- │ --- │
│ u32 │ u32 │ u32 │ u32 │ u32 │
╞═════════╪══════════╪══════════╪═════════╪════════╡
│ 0 │ 0 │ 0 │ 0 │ 0 │
└─────────┴──────────┴──────────┴─────────┴────────┘
高价值订单数:386521
各省份高价值用户统计(前10名):
shape: (10, 3)
┌──────────┬─────────┬─────────────┐
│ province │ 订单数 │ 总销售额 │
│ --- │ --- │ --- │
│ str │ u32 │ f64 │
╞══════════╪═════════╪═════════════╡
│ 广东 │ 68923 │ 58762980.5 │
│ 浙江 │ 45218 │ 39876540.2 │
│ 江苏 │ 41892 │ 36521980.8 │
│ 上海 │ 38765 │ 32456789.1 │
│ 北京 │ 35621 │ 30123456.7 │
└──────────┴─────────┴─────────────┘
整个流程仅需数秒即可完成百万行数据的处理,代码清晰简洁,易于理解和上手。
总结:为什么值得学习 Polars?
- 性能卓越:速度远超 Pandas,能高效处理千万级乃至更大规模的数据集,告别长时间等待。
- 语法亲和:与 Pandas 高度相似,已有 Pandas 基础的用户可以近乎无缝地过渡,学习成本低。
- 内存高效:独特的惰性执行模式能够优化执行计划,在处理超大数据时有效管理内存,运行更流畅。
- 功能全面:支持筛选、聚合、排序、连接等各类数据处理需求,并兼容多种数据格式的读写。
- 顺应趋势:随着数据量持续增长,对高性能数据处理工具的需求日益迫切,掌握 Polars 将成为 数据分析 领域的一项有价值的技能。