事实核验:2026-08-16 · 状态:现行内容

记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。

warning 适用边界与维护说明

本文适用于 Polars Python 表达式与 DataFrame 常用操作的入门学习,示例数据在正文中完整给出,不构成生产级数据处理或金额精度方案。实际使用需结合所安装版本核对 API,尤其是连接验证与 streaming 支持;金额类型、连接匹配率和日期解析失败率仍需按业务要求检查。本次仅作全文结构审阅,未执行示例、核验外部文档或检查链接可达性。

Polars表达式与常用数据操作

abstract 学习目标

用表达式而非逐行 Python 函数完成选择、过滤、派生列、分组、连接和空值处理;理解表达式与执行上下文的关系。

Polars 的核心不是“方法名字像 Pandas”,而是表达式 DSL。表达式描述一段列变换,本身不会独立产生结果;放入 select、with_columns、filter、group_by(...).agg(...) 等上下文后才按上下文执行。先阅读 Polars学习路线图。

1. 构造数据与查看 schema

import polars as pl

orders = pl.DataFrame(
    {
        "order_id": [1, 2, 3, 4],
        "status": ["paid", "cancelled", "paid", None],
        "amount": [99.0, 30.0, 120.0, 50.0],
        "customer_id": [10, 20, 20, 30],
    }
)

print(orders.schema)

预期能看到四列及其类型。实际项目应检查推断是否符合业务,尤其是金额、nullable integer、时间戳和分类列。相关数据结构可对照 Pandas数据结构。

2. select 与 with_columns

select 只返回指定表达式产生的列;with_columns 保留原列并新增或替换列。

summary = orders.select(
    pl.len().alias("rows"),
    pl.col("amount").sum().alias("amount_sum"),
    pl.col("customer_id").n_unique().alias("customers"),
)

enriched = orders.with_columns(
    (pl.col("amount") * 1.06).round(2).alias("amount_with_tax"),
    pl.col("status").fill_null("unknown"),
)

预期 summary 为一行,rows=4、amount_sum=299.0、customers=3;enriched 保留四行并新增含税金额,同时填充状态空值。同一个 with_columns 中的表达式应按输入 schema 理解,不要依赖某个新列立即被旁边另一个表达式引用;需要有先后依赖时拆成两步。

3. filter 与条件表达式

paid = orders.filter(pl.col("status") == "paid")

flagged = orders.with_columns(
    pl.when(pl.col("amount") >= 100)
    .then(pl.lit("high"))
    .otherwise(pl.lit("normal"))
    .alias("amount_level")
)

预期 paid 只有订单 1、3;订单 3 被标记为 high。布尔条件中的空值不会自动等于 False 的业务含义,必须决定是过滤、填充还是单独保留未知状态。

4. 分组聚合

by_status = (
    orders
    .group_by("status")
    .agg(
        pl.len().alias("rows"),
        pl.col("amount").sum().alias("amount_sum"),
        pl.col("amount").mean().alias("amount_avg"),
    )
    .sort("status", nulls_last=True)
)

每个聚合表达式都在分组上下文中计算。group_by 不保证业务需要的输出顺序,因此展示或测试时应显式 sort。新增分组字段会改变粒度,必须重新核对唯一键与行数。

5. 连接与列名冲突

customers = pl.DataFrame(
    {"customer_id": [10, 20], "segment": ["new", "vip"]}
)

joined = orders.join(
    customers,
    on="customer_id",
    how="left",
    validate="m:1",
)

validate="m:1" 表达多对一预期,能帮助发现右表重复键。预期客户 30 的 segment 为 null。真实任务还应检查连接前后行数和未匹配率;验证语义及 streaming 支持需按当前 API 文档复查。

6. 字符串、日期与空值

events = pl.DataFrame(
    {"raw_time": ["2026-08-16 10:00:00", None], "code": [" a ", "B"]}
).with_columns(
    pl.col("raw_time").str.to_datetime(strict=False).alias("event_time"),
    pl.col("code").str.strip_chars().str.to_uppercase().alias("code_clean"),
)

strict=False 会把无法解析的值转为 null,适合探索但可能掩盖脏数据。生产处理应额外统计“原值非空但解析后为空”的数量。系统化清洗见 Pandas数据清洗。

7. 避免 Python UDF

优先使用原生表达式,因为 Polars 可以分析、并行化和优化它们。map_elements 等 Python UDF 通常更慢,也可能限制优化。只有原生表达式确实无法表达、并且有性能基准和返回类型测试时才使用。

8. 练习与验收

  1. 为订单增加折扣后金额,禁止使用 apply 或 Python 循环。
  2. 按客户聚合 GMV 和订单数,显式排序并写预期结果。
  3. 制造重复客户维表,用连接验证发现违反 m:1。
  4. 解析一列混合日期,统计失败率并保留原始字段。
  5. 对金额列比较 Float64 与 Decimal 的 schema 和结果。

9. 延伸阅读

官方来源