Polars:展开列表列前匹配每行多列表的元素数量
解决Polars多列表列补全长度后explode的问题
问题原因
你原来的代码报错是因为pl.lit只能处理静态常量,无法基于动态计算的表达式(比如每行的列表长度差)生成列表。另外,原列表是i64类型,补全空字符串会导致类型不匹配,引发转换错误。
解决方案
步骤1:计算每行两个列表的最大长度
先新增一列max_len,存储每行中a和b列表的最大长度:
import polars as pl df = pl.DataFrame({ "a": [[1, 2], [3], [4, 5], [1]], "b": [[4, 5, 7], [6], [4, 5], [3, 2]] }) # 计算每行的最大列表长度 df = df.with_columns(max_len=pl.max_horizontal(pl.col("a").list.len(), pl.col("b").list.len()))
步骤2:补全短列表到最大长度
使用pl.list.repeat动态生成对应长度的占位元素(推荐用None匹配原i64类型的Null值,或转换类型后用空字符串):
# 补全a列:长度不足时拼接None列表 # 补全b列:同理 df = df.with_columns( a=pl.when(pl.col("a").list.len() < pl.col("max_len")) .then(pl.col("a").list.concat(pl.list.repeat(None, pl.col("max_len") - pl.col("a").list.len()))) .otherwise(pl.col("a")), b=pl.when(pl.col("b").list.len() < pl.col("max_len")) .then(pl.col("b").list.concat(pl.list.repeat(None, pl.col("max_len") - pl.col("b").list.len()))) .otherwise(pl.col("b")) )
步骤3:执行explode操作
此时所有列表列长度一致,可以正常explode:
result = df.explode(["a", "b"]) print(result)
输出结果:
shape: (8, 4) ┌──────┬──────┬───────┬─────────┐ │ a ┆ b ┆ alens ┆ max_len │ │ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ u32 ┆ u32 │ ╞══════╪══════╪═══════╪═════════╡ │ 1 ┆ 4 ┆ 2 ┆ 3 │ │ 2 ┆ 5 ┆ 2 ┆ 3 │ │ null ┆ 7 ┆ 2 ┆ 3 │ │ 3 ┆ 6 ┆ 1 ┆ 1 │ │ 4 ┆ 4 ┆ 2 ┆ 2 │ │ 5 ┆ 5 ┆ 2 ┆ 2 │ │ 1 ┆ 3 ┆ 1 ┆ 2 │ │ null ┆ 2 ┆ 1 ┆ 2 │ └──────┴──────┴───────┴─────────┘
可选:补全空字符串(需转换类型)
如果一定要用空字符串作为占位,需先将列表列转换为String类型:
df = df.with_columns( a=pl.col("a").cast(pl.String), b=pl.col("b").cast(pl.String), max_len=pl.max_horizontal(pl.col("a").list.len(), pl.col("b").list.len()) ).with_columns( a=pl.when(pl.col("a").list.len() < pl.col("max_len")) .then(pl.col("a").list.concat(pl.list.repeat("", pl.col("max_len") - pl.col("a").list.len()))) .otherwise(pl.col("a")), b=pl.when(pl.col("b").list.len() < pl.col("max_len")) .then(pl.col("b").list.concat(pl.list.repeat("", pl.col("max_len") - pl.col("b").list.len()))) .otherwise(pl.col("b")) ).explode(["a", "b"])
关键说明
- 避免用
pl.lit处理动态生成的列表:pl.lit仅适用于静态常量,动态长度的列表需用Polars内置的列表生成函数(如pl.list.repeat)。 - 保持类型一致:补全元素的类型必须和原列表类型匹配,否则会引发类型转换错误。
内容的提问来源于stack exchange,提问作者DOOM
相关产品推荐
相关产品推荐

