跳转至

Polars 数据处理

一句话概述:Polars 是用Rust写的高性能DataFrame库,比pandas快30倍以上,是数据分析领域的"新星"。

核心知识点表

概念白话解释
DataFrame表格数据结构,类似pandas的DataFrame但性能强很多
LazyFrame懒执行的DataFrame,先积攒操作再一次性计算(更快)
Expression表达式,Polars的核心操作方式(类似SQL的列操作)
Series一列数据,类似pandas的Series
Context上下文,决定表达式在哪里执行(select/filter/group_by)
Streaming流式模式,处理超出内存的数据
Scan懒读取,不立即加载全部数据到内存

版本信息(2026年5月)

  • Python版本:Polars 1.40.1
  • Rust版本:0.53.0
  • 亮点:Polars Cloud、新流式引擎、Iceberg/Delta集成

安装配置

# 安装Polars(只需一行)
pip install polars  # 基础版

# 安装带所有功能的版本
pip install 'polars[all]'  # 包含Excel、数据库、时区等额外功能

# 验证
python -c "import polars as pl; print(pl.__version__)"

基本使用

创建DataFrame

import polars as pl  # 约定简写为pl(类似pandas的pd)

# 从字典创建
df = pl.DataFrame({
    "name": ["Alice", "Bob", "Charlie", "Diana"],  # 姓名
    "age": [25, 30, 35, 28],                        # 年龄
    "city": ["北京", "上海", "广州", "深圳"],         # 城市
    "salary": [15000, 20000, 25000, 18000],          # 薪资
})

print(df)          # 打印表格(自带漂亮格式)
print(df.schema)   # 查看数据类型
print(df.shape)    # (行数, 列数)
print(df.columns)  # 列名列表

读取数据

# 读取CSV
df = pl.read_csv("data.csv")  # 急切模式:立即读取全部数据

# 懒读取CSV(推荐,大文件更高效)
lf = pl.scan_csv("data.csv")  # 不立即读取,返回LazyFrame

# 读取Parquet(最推荐的格式)
df = pl.read_parquet("data.parquet")
lf = pl.scan_parquet("data.parquet")  # 懒读取

# 读取JSON
df = pl.read_json("data.json")

# 读取Excel(需要安装openpyxl)
df = pl.read_excel("data.xlsx", sheet_name="Sheet1")

核心操作

# ===== 选择列 =====
df.select("name", "age")  # 选择指定列
df.select(pl.col("name"), pl.col("age") + 1)  # 用表达式选择

# ===== 过滤行 =====
df.filter(pl.col("age") > 28)  # 年龄大于28
df.filter(
    (pl.col("age") > 25) & (pl.col("city") == "上海")  # 多条件
)

# ===== 添加新列 =====
df = df.with_columns(
    (pl.col("salary") * 12).alias("annual_salary"),  # 年薪 = 月薪 * 12
    pl.when(pl.col("age") < 30)  # 条件判断
        .then(pl.lit("年轻"))
        .otherwise(pl.lit("资深"))
        .alias("age_group"),  # 年龄分组
)

# ===== 排序 =====
df.sort("salary", descending=True)  # 按薪资降序
df.sort(["city", "age"])  # 多列排序

# ===== 分组聚合 =====
df.group_by("city").agg(
    pl.col("salary").mean().alias("avg_salary"),   # 平均薪资
    pl.col("name").count().alias("person_count"),  # 人数
    pl.col("age").max().alias("max_age"),           # 最大年龄
)

# ===== 去重 =====
df.unique(subset=["email"])  # 按email去重
df.n_unique()  # 每列唯一值数量

LazyFrame(懒执行,推荐)

# 懒执行的优势:Polars会优化整个查询计划再执行,比急切模式更快

result = (
    pl.scan_csv("big_data.csv")  # 1. 懒读取(不加载数据)
    .filter(pl.col("status") == "active")  # 2. 过滤(还没执行)
    .group_by("department")  # 3. 分组(还没执行)
    .agg(
        pl.col("salary").mean().alias("avg_salary"),
        pl.col("id").count().alias("count"),
    )  # 4. 聚合(还没执行)
    .sort("avg_salary", descending=True)  # 5. 排序(还没执行)
    .collect()  # 6. 触发执行!Polars优化后一次性计算
)

# 查看查询计划(理解Polars怎么优化你的查询)
lf = pl.scan_csv("data.csv").filter(pl.col("age") > 25)
print(lf.explain())  # 打印优化后的执行计划

高级用法

窗口函数

# 在每个部门内排名
df = df.with_columns(
    pl.col("salary")
        .rank(descending=True)  # 降序排名
        .over("department")     # 在department组内执行
        .alias("salary_rank"),  # 部门内薪资排名
)

# 移动平均
df = df.with_columns(
    pl.col("value")
        .rolling_mean(window_size=7)  # 7天移动平均
        .alias("ma_7"),
)

Join连接

# 内连接
result = df_users.join(
    df_orders,
    on="user_id",    # 连接键
    how="inner",     # inner/left/right/full/cross/semi/anti
)

# 左连接(保留左表所有行)
result = df_users.join(df_orders, on="user_id", how="left")

# Anti Join(找出没有订单的用户)
no_orders = df_users.join(df_orders, on="user_id", how="anti")

字符串操作

df = df.with_columns(
    pl.col("name").str.to_uppercase().alias("name_upper"),  # 转大写
    pl.col("email").str.contains("@gmail").alias("is_gmail"),  # 包含判断
    pl.col("text").str.replace_all(r"\s+", " ").alias("clean_text"),  # 正则替换
    pl.col("date_str").str.to_date("%Y-%m-%d").alias("date"),  # 字符串转日期
)

时间序列

# 创建时间序列
df = pl.DataFrame({
    "date": pl.date_range(  # 生成日期范围
        start=pl.date(2026, 1, 1),
        end=pl.date(2026, 12, 31),
        interval="1d",  # 每天
        eager=True,
    ),
    "value": range(365),
})

# 按月聚合
monthly = df.group_by_dynamic(
    "date",
    every="1mo",  # 每月
).agg(
    pl.col("value").sum().alias("monthly_total"),
    pl.col("value").mean().alias("monthly_avg"),
)

处理超大数据(流式模式)

# 当数据超出内存时,用流式模式
result = (
    pl.scan_csv("huge_file.csv")  # 懒读取
    .filter(pl.col("amount") > 100)
    .group_by("category")
    .agg(pl.col("amount").sum())
    .collect(engine="streaming")  # 流式执行,分块处理不爆内存
)

与pandas互转

# pandas → Polars
import pandas as pd
pandas_df = pd.DataFrame({"a": [1, 2, 3]})
polars_df = pl.from_pandas(pandas_df)  # pandas转Polars

# Polars → pandas
pandas_df = polars_df.to_pandas()  # Polars转pandas

常见报错与解决

报错信息原因解决方案
ColumnNotFoundError列名写错df.columns查看所有列名
SchemaError: type mismatch数据类型不匹配.cast(pl.Int64)转换类型
ComputeError: invalid operation对不支持的类型做了操作检查列类型df.schema
OutOfMemoryError数据太大scan_*+collect(engine="streaming")
InvalidOperationError在LazyFrame上调了Eager方法.collect()再操作,或用Lazy兼容的方法
import polars 报错版本不兼容pip install --upgrade polars

速查表

# ===== 读写 =====
pl.read_csv("f.csv")           # 读CSV
pl.scan_csv("f.csv")           # 懒读CSV
pl.read_parquet("f.parquet")   # 读Parquet
df.write_csv("out.csv")        # 写CSV
df.write_parquet("out.parquet") # 写Parquet

# ===== 基本操作 =====
df.select("col1", "col2")     # 选列
df.filter(pl.col("x") > 10)   # 过滤
df.with_columns(...)           # 添加/修改列
df.sort("col", descending=True) # 排序
df.group_by("col").agg(...)    # 分组聚合
df.join(df2, on="key")         # 连接
df.unique(subset=["col"])      # 去重
df.head(10)                    # 前10行
df.sample(100)                 # 随机抽样100行

# ===== 常用表达式 =====
pl.col("name")                # 引用列
pl.lit(42)                     # 字面量
pl.when(...).then(...).otherwise(...)  # 条件
pl.col("x").alias("new_name")  # 重命名
pl.col("x").cast(pl.Float64)   # 类型转换
pl.col("x").is_null()          # 判断空值
pl.col("x").fill_null(0)       # 填充空值

同类工具对比

特性PolarspandasDuckDBSpark
性能★★★★★★★★★★★★★★★
内存效率★★★★★★★★★★★★★★★
API风格表达式链式命令式SQL混合
并行自动多线程单线程自动多线程分布式
数据规模单机GB-TB单机GB以下单机GB-TB集群TB+
学习曲线中等最低低(会SQL就行)较高
生态快速增长最成熟增长中成熟

面试建议:Polars是近年最火的数据处理新星。面试时可以说"Polars的核心优势是Rust写的查询引擎 + 懒执行优化 + 自动并行"。和pandas对比时重点讲:1)不可变数据(没有inplace操作);2)表达式API比pandas更一致;3)懒执行让Polars能全局优化查询。