找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1096

积分

0

好友

142

主题
发表于 9 小时前 | 查看: 2| 回复: 0

在使用 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?

  1. 性能卓越:速度远超 Pandas,能高效处理千万级乃至更大规模的数据集,告别长时间等待。
  2. 语法亲和:与 Pandas 高度相似,已有 Pandas 基础的用户可以近乎无缝地过渡,学习成本低。
  3. 内存高效:独特的惰性执行模式能够优化执行计划,在处理超大数据时有效管理内存,运行更流畅。
  4. 功能全面:支持筛选、聚合、排序、连接等各类数据处理需求,并兼容多种数据格式的读写。
  5. 顺应趋势:随着数据量持续增长,对高性能数据处理工具的需求日益迫切,掌握 Polars 将成为 数据分析 领域的一项有价值的技能。



上一篇:基于ESP8266 D1 Mini与OLED屏,打造可触摸交互的桌面电子眼睛
下一篇:深入解析:Docker容器共享宿主内核,为何仍需Ubuntu镜像作用
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-3 18:36 , Processed in 0.356964 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表