如何在Polars中实现两展开列的Left Join以获取目标结果
用Polars实现列表展开后的左连接匹配
给定如下Polars DataFrame,a列为整数列表,b列为结构体列表:
import polars as pl df = pl.DataFrame({ "a": [[1, 2], [3]], "b": [ [{"id": 1, "x": 1}, {"id": 3, "x": 3}], [{"id": 3, "x": 4}] ] })
数据结构如下:
┌───────────┬─────────────────┐ │ a ┆ b │ │ --- ┆ --- │ │ list[i64] ┆ list[struct[2]] │ ╞═══════════╪═════════════════╡ │ [1, 2] ┆ [{1,1}, {3,3}] │ │ [3] ┆ [{3,4}] │ └───────────┴─────────────────┘
需求是:
- 将
a列展开,每个元素对应一行 - 若
b列的结构体列表中存在id等于a元素的项,则将对应x值填入b列 - 否则
b列值为null
原来通过两次explode再过滤的方式得到的是内连接结果,丢失了a=2这类无匹配的行。要实现类似左连接的效果,可以用以下高效方法:
方法一:列表内筛选匹配项
先展开a列,再对每行的b列表筛选出id匹配当前a的结构体,提取x值后取第一个(无匹配则返回null):
result = df.explode("a").with_columns( pl.col("b") .list.eval(pl.element().struct.field("x").filter(pl.element().struct.field("id") == pl.col("a"))) .list.first() .alias("b") ) print(result)
方法二:转字典后直接取值
利用struct.to_dict将结构体列表转换为以id为键、x为值的字典,再通过list.get根据a的值获取对应x(不存在则自动返回null):
result = df.explode("a").with_columns( pl.col("b") .list.struct.to_dict("id", "x") .list.get(pl.col("a")) .alias("b") ) print(result)
两种方法都能得到期望的结果:
┌─────┬──────┐ │ a ┆ b │ │ --- ┆ --- │ │ i64 ┆ i64 │ ╞═════╪══════╡ │ 1 ┆ 1 │ │ 2 ┆ null │ │ 3 ┆ 4 │ └─────┴──────┘
这两种方式无需生成大量中间行,直接在原行内完成匹配,性能比两次explode后过滤更高效,尤其适合处理大规模数据。
内容的提问来源于stack exchange,提问作者Filippo Vitale
相关产品推荐
相关产品推荐

