Chapter 09

字符串 · 列表 · 结构体

掌握 str 命名空间的文本处理与正则、list 命名空间的变长数组操作、struct 结构体与 explode 展开——玩转半结构化数据。

9.1 命名空间:类型专属方法

命名空间(Namespace)
Polars 把某类型专属的方法收在一个前缀下,如 .str.*(字符串)、.list.*(列表)、.dt.*(时间)、.struct.*(结构体)。表达式先选列,再进命名空间调方法。
str 命名空间
Utf8 列的文本方法:大小写、切片、替换、正则、拆分、拼接、类型转换等。
list 命名空间
List 列(每格一个变长数组)的方法:取元素、长度、求和、去重、连接、判断包含等。
struct 命名空间
Struct 列(每格若干命名字段)的方法:取字段、重命名、展开成多列。类似操作一列 JSON 对象。
explode
把 List 列"炸开":一行中列表的每个元素各占一行,其余列复制。是长宽变换的关键。
正则(regex)
Polars 的字符串正则基于 Rust 的 regex 库,语法接近 PCRE,速度快,用于 contains/extract/replace_all

9.2 str:字符串处理

import polars as pl

df = pl.DataFrame({"email": ["Alice@QQ.com", "bob@163.com"]})

df.with_columns(
    pl.col("email").str.to_lowercase().alias("lower"),
    pl.col("email").str.len_chars().alias("len"),
    pl.col("email").str.contains("qq").alias("is_qq"),   # 正则匹配
    # 提取 @ 前的用户名(正则捕获组)
    pl.col("email").str.extract(r"^([^@]+)@", 1).alias("user"),
    # 按 @ 拆分成 list
    pl.col("email").str.split("@").alias("parts"),
    # 正则替换
    pl.col("email").str.replace_all(r"\.com$", ".cn").alias("cn"),
)

9.3 list:变长数组

df = pl.DataFrame({"nums": [[1, 2, 3], [4, 5], []]})

df.with_columns(
    pl.col("nums").list.len().alias("n"),
    pl.col("nums").list.sum().alias("sum"),
    pl.col("nums").list.first().alias("head"),
    pl.col("nums").list.get(0).alias("idx0"),
    pl.col("nums").list.contains(2).alias("has_2"),
    # 对列表每个元素跑表达式
    pl.col("nums").list.eval(pl.element() * 10).alias("x10"),
)

9.4 explode:列表炸开成行

df.explode("nums")
# [1,2,3] 那行变成 3 行,每行 nums 为 1/2/3

# 反向:多行聚回列表(配 group_by)
df.explode("nums").group_by("id").agg(pl.col("nums"))

9.5 struct:结构体列

# 把多列打包成一个 struct 列
df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
df2 = df.select(
    pl.struct(["x", "y"]).alias("point")
)

# 取 struct 里的某个字段
df2.select(pl.col("point").struct.field("x"))

# 把 struct 展开回多列
df2.unnest("point")

# value_counts 返回的就是 struct,可直接 unnest
df.select(pl.col("x").value_counts()).unnest("x")
struct 的典型用途

需要"一个表达式返回多个值"时用 struct 打包,如同时算 min 和 max、或对多列做同一变换后再展开。读取嵌套 JSON 时,对象字段天然映射成 struct,用 unnest 拍平即可。

9.6 正则速查

方法作用
str.contains(pat)是否匹配(返回 Boolean)
str.extract(pat, i)提取第 i 个捕获组
str.extract_all(pat)提取所有匹配(返回 list)
str.replace(pat, s)替换首个匹配
str.replace_all(pat, s)替换所有匹配
str.count_matches(pat)匹配次数
字面量匹配

contains 默认把参数当正则。若要匹配含 .* 等特殊字符的字面字符串,传 literal=True,否则 . 会被当成"任意字符"。

9.7 小结与下一步