本文介绍如何使用 polars 的 `pivot` 方法,将长格式稀疏数据(id-key-value 三元组)高效转换为宽格式列向量表示,适用于大规模稀疏特征工程场景。
在处理稀疏特征数据(如用户行为、基因表达、推荐系统 item-tag 关系等)时,原始存储常采用紧凑的三列结构(id, key, value),以节省空间并便于增量更新;但在建模或矩阵运算阶段,往往需要将其展开为宽表形式——即每个唯一 key 成为一列,id 作为行索引,对应 value 填入单元格,缺失值自动填充为 null。Polars 提供了原生、高性能的 pivot 操作来完成这一转换,远优于手动分组拼接或循环构造。
只需一行代码即可完成转换:
import polars as pl
df = pl.from_repr("""
┌─────┬─────┬───────┐
│ id ┆ key ┆ value │
│ --- ┆ --- ┆ --- │
│ str ┆ str ┆ i64 │
╞═════╪═════╪═══════╡
│ a ┆ m1 ┆ 1 │
│ a ┆ m2 ┆ 2 │
│ a ┆ m3 ┆ 1 │
│ b ┆ m2 ┆ 4 │
│ c ┆ m1 ┆ 2 │
│ c ┆ m3 ┆ 6 │
│ d ┆ m4 ┆ 4 │
│ e ┆ m2 ┆ 1 │
└─────┴─────┴───────┘
""")
result = df.pivot(on="key", index="id", values="value")
print(result)输出为标准宽表(5 行 × 5 列),自动对齐所有 key(m1–m4)作为列名,并保留原始数据类型(i64),缺失位置统一为 null:
shape: (5, 5) ┌─────┬──────┬──────┬──────┬──────┐ │ id ┆ m1 ┆ m2 ┆ m3 ┆ m4 │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ i64 ┆ i64 ┆ i64 │ ╞═════╪══════╪══════╪══════╪══════╡ │ a ┆ 1 ┆ 2 ┆ 1 ┆ null │ │ b ┆ null ┆ 4 ┆ null ┆ null │ │ c ┆ 2 ┆ null ┆ 6 ┆ null │ │ d ┆ null ┆ null ┆ null ┆ 4 │ │ e ┆ null ┆ 1 ┆ null ┆ null │ └─────┴──────┴──────┴──────┴──────┘
? 参数说明: on="key":指定要“展开”的列(即新列名来源); index="id":指定行标识列(即新表的行索引); values="value":指定填充单元格的数值列(默认为 value,可省略)。
df.pivot(on="key", index="id", values="value", aggregate_function=pl.col("value").sum())将稀疏长表转为宽表是特征工程中的高频操作。Polars 的 pivot() 方法以简洁语法、明确语义和卓越性能,成为该任务的理想选择。掌握其核心参数与限制(尤其是 eager/lazy 差异),可大幅提升数据预处理 pipeline 的可读性与执行效率。对于超大规模场景,建议配合 scan_parquet() + collect() 分块 pivot,避免单次内存峰值过高。