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

3714

积分

0

好友

492

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

今天不聊虚的,整点硬货。

有个东西叫 Polars,你们听说过没?这两年在数据圈火得一塌糊涂。简单说就一句话:比 pandas 快 5 到 50 倍

别急着说“我不信”,往下看。

01 | 先给你们看个真实的测试结果

我自己拿 100 万行的销售数据跑过分组聚合:

pandas:  4.23秒
Polars:  0.31秒

差了 13 倍

就是同一个需求,同一台电脑,同样的代码逻辑,就因为换了个库,快了这么多。

pandas 处理百万级数据还在喘气的时候,Polars 已经叼着烟喝着茶把活干完了 😏

为什么这么快?

Polars 是 Rust 写的,pandas 是 C 写的。

Rust 那家伙,天生支持多线程,内存管理又精细,执行效率比 C 高出一大截。这不是吹的,是血统优势。

02 | 先看代码对比,心里有个数

假设你有个 CSV 文件,100 万行销售数据。

Pandas 版本:

import pandas as pd

df = pd.read_csv('sales.csv')
df['date'] = pd.to_datetime(df['date'])
df['month'] = df['date'].dt.to_period('M')
result = df.groupby('month')['amount'].sum()

print(result)

Polars 版本:

import polars as pl

df = pl.read_csv('sales.csv')
result = (
    df
    .with_columns(pl.col('date').str.to_date())
    .with_columns(pl.col('date').dt.month().alias('month'))
    .group_by('month')
    .agg(pl.col('amount').sum())
)

print(result)

看出区别没?

pandas 要分好几步赋值,中间还产生临时列。Polars 一个括号链下来,干净利落,管道式操作,读起来跟说话一样。

03 | 安装?3 秒钟搞定

pip install polars

对,就这么一行。

如果你是 conda 用户:

conda install polars -c conda-forge

装完验证一下:

import polars as pl
print(pl.__version__)
# 输出:1.22.0(举例)

没报错就说明装好了,可以开始浪了。

04 | 两个核心概念:Series 和 DataFrame

Polars 的数据结构跟 pandas 差不多,学过 pandas 的鱼油可以直接上手。

4.1 Series:就是一维数组

import polars as pl

s = pl.Series("姓名", ["张三", "李四", "王五"])
print(s)

输出:

shape: (3,)
Series: '姓名' [str]
[
    "张三"
    "李四"
    "王五"
]

就是一组数据,类似于 Excel 里的一列。

4.2 DataFrame:就是表格

import polars as pl

df = pl.DataFrame({
    "姓名": ["张三", "李四", "王五"],
    "年龄": [25, 30, 35],
    "城市": ["北京", "上海", "深圳"]
})

print(df)

输出:

shape: (3, 3)
┌──────┬──────┬──────┐
│ 姓名  ┆ 年龄  ┆ 城市  │
│ str  ┆ i64  ┆ str  │
╞══════╪══════╪══════╡
│ 张三  ┆ 25   ┆ 北京  │
│ 李四  ┆ 30   ┆ 上海  │
│ 王五  ┆ 35   ┆ 深圳  │
└──────┴──────┴──────┘

这个表格打印出来比 pandas 好看太多了,我第一次用的时候差点感动哭 😭

05 | 读取数据:这些方法要记住

5.1 读 CSV(最常用)

# 最基本的
df = pl.read_csv("data.csv")

# 指定分隔符
df = pl.read_csv("data.csv", separator=";")

# 跳过前几行
df = pl.read_csv("data.csv", skip_rows=2)

# 只读取需要的列
df = pl.read_csv("data.csv", columns=["name", "age", "city"])

# 自动解析日期
df = pl.read_csv("data.csv", try_parse_dates=True)

5.2 读 Parquet(比 CSV 快很多)

Parquet 是一种列式存储格式,大数据场景下比 CSV 快几倍到几十倍:

df = pl.read_parquet("data.parquet")

5.3 读 JSON

df = pl.read_json("data.json")

5.4 懒加载模式(大文件必杀技)

这是 Polars 的杀手锏功能!

# scan_csv 不会立即执行,只是"规划"操作
lf = pl.scan_csv("big_data.csv")

# 查看执行计划(不会真正跑)
print(lf.explain())

# 调用 collect 才真正执行
df = lf.collect()

scan_csv 会自动做 谓词下推(predicate pushdown),意思是大文件它只读取你真正需要的数据,不会傻乎乎全读进内存。

数据量上了千万行的鱼油们,这一点能救你一命。

06 | 基础查询:filter、select、with_columns

6.1 看数据

df.head()      # 看前5行
df.tail()      # 看后5行
df.glimpse()   # 快速瞥一眼
df.describe()  # 统计摘要

6.2 筛选行:filter

# 筛选年龄大于25的
df.filter(pl.col("年龄") > 25)

# AND条件:年龄大于25 且 城市是北京
df.filter((pl.col("年龄") > 25) & (pl.col("城市") == "北京"))

# OR条件
df.filter((pl.col("年龄") < 30) | (pl.col("城市") == "深圳"))

注意:&| 要加括号,否则会报错。Python 的运算符优先级会坑你。

6.3 选择列:select

# 选择单列
df.select("姓名")

# 选择多列
df.select(["姓名", "城市"])

# 用表达式选(更灵活)
df.select(pl.col("姓名"), pl.col("年龄") * 2)

6.4 新增/修改列:with_columns

# 新增一列:年龄+1
df.with_columns((pl.col("年龄") + 1).alias("年龄+1"))

# 修改列:姓名全变大写
df.with_columns(pl.col("姓名").str.to_uppercase().alias("姓名大写"))

# 一次做多个变换
df.with_columns(
    pl.col("年龄").alias("原年龄"),
    (pl.col("年龄") + 10).alias("年龄加10"),
    pl.col("城市").str.lengths().alias("城市字符数")
)

07 | 排序:sort

# 按年龄升序
df.sort("年龄")

# 按年龄降序
df.sort("年龄", descending=True)

# 多字段排序:先按城市,再按年龄
df.sort(["城市", "年龄"], descending=[False, True])

08 | 分组聚合:group_by + agg(超级重要)

这个是数据分析的灵魂操作,必须拿下。

# 模拟销售数据
sales_df = pl.DataFrame({
    "月份": ["1月", "1月", "2月", "2月", "3月"],
    "产品": ["A", "B", "A", "B", "A"],
    "销售额": [100, 200, 150, 250, 180]
})

# 按月份分组,求总销售额
result = (
    sales_df
    .group_by("月份")
    .agg(pl.col("销售额").sum().alias("总销售额"))
)

print(result)

输出:

shape: (3, 2)
┌──────┬──────────┐
│ 月份  ┆ 总销售额  │
│ str  ┆ i64      │
╞══════╪══════════╡
│ 1月   ┆ 300      │
│ 2月   ┆ 400      │
│ 3月   ┆ 180      │
╞══════╧══════════┡

分组聚合就两句话:group_by 分组,agg 算指标。记住了吧?🐟

09 | 关联表:join

类似 SQL 里的 JOIN,把两张表拼在一起:

# 客户表
customers = pl.DataFrame({
    "客户ID": [1, 2, 3],
    "客户名": ["张三", "李四", "王五"]
})

# 订单表
orders = pl.DataFrame({
    "客户ID": [1, 2, 2],
    "订单金额": [100, 200, 300]
})

# 左连接
result = customers.join(orders, on="客户ID", how="left")

print(result)

输出:

shape: (3, 3)
┌────────┬────────┬──────────┐
│ 客户ID  ┆ 客户名  ┆ 订单金额  │
│ i64    ┆ str    ┆ i64      │
╞════════╪════════╪══════════╡
│ 1      ┆ 张三    ┆ 100      │
│ 2      ┆ 李四    ┆ 200      │
│ 2      ┆ 李四    ┆ 300      │
└────────┴────────┴──────────┘

Polars 的 join 和 SQL 的逻辑一模一样,左连接就是以左边为准,右边没有的填 NULL。

10 | 管道运算符:代码读起来像说话

Polars 支持 |> 管道运算符,代码可读性直接起飞:

# 不用管道:嵌套地狱,眼睛要瞎了
result = sort(with_columns(filter(df, pl.col("年龄") > 25), pl.col("年龄") * 2), "年龄")

# 用管道:跟读句子一样,从左到右
result = (
    df
    .filter(pl.col("年龄") > 25)
    .with_columns((pl.col("年龄") * 2).alias("年龄翻倍"))
    .sort("年龄")
)

哪个好读?不用说大家都知道。

11 | 避坑指南

坑 1:别来回转换 pandas 和 Polars

# ❌ 不好:反复横跳,效率没了
df_pandas = df.to_pandas()
df_polars = pl.from_pandas(df_pandas)

# ✅ 好:在Polars里一气呵成
df.filter(...).with_columns(...).sort(...)

坑 2:字符串操作要用 .str

# ✅ 正确
df.with_columns(pl.col("name").str.to_uppercase())

# ❌ 错误
df.with_columns(pl.col("name").to_uppercase())

Polars 的字符串操作要加 .str,否则它不认识你是想搞字符串操作还是列操作。

坑 3:大文件用 LazyFrame

# 小文件:直接读
df = pl.read_csv("small.csv")

# 大文件:scan + collect
df = pl.scan_csv("big.csv").filter(pl.col("age") > 20).collect()

12 | 实战练习 🐟

练习题:

有个销售记录 CSV(sales.csv),包含这些字段:

  • date:日期
  • product:产品名
  • category:类别
  • amount:销售额
  • quantity:销售数量

用 Polars 完成:

  1. 读取 CSV
  2. 筛选 category == "电子产品" 的记录
  3. 按产品分组,计算总销售额和总销售数量
  4. 按总销售额降序排序
  5. 保留销售额前 3 的产品

答案下期公布! 先自己动手做,做出来的鱼油评论区见 💪

13 | 总结

今天学了什么:

  1. 为什么快:Rust 血统,多线程,列式存储
  2. 两种数据结构:Series(一维)、DataFrame(二维表格)
  3. 读取数据:read_csv、read_parquet、scan_csv(懒加载)
  4. 基础操作:filter、select、with_columns、sort
  5. 分组聚合:group_by + agg
  6. 关联表:join
  7. 管道运算符:让代码优雅

下期预告: 表达式引擎,像写 SQL 一样写 Python —— 敬请期待!


你们平时用什么处理数据?pandas 还是 Polars?或者 Excel?在云栈社区聊聊你的数据处理利器吧!




上一篇:AI Agent时代的格式选择:为何HTML比Markdown更高效
下一篇:eFuse技术详解:从原理到选型,如何用电子保险丝实现可设计的电路保护?
您需要登录后才可以回帖 登录 | 立即注册

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

GMT+8, 2026-5-15 06:41 , Processed in 0.846918 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

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