如何在Polars中无需循环自动展开多层嵌套Struct列?
扁平化Polars中多层嵌套Struct的更优方案
你当前的循环方案虽然可行,但Polars提供了更简洁的函数式实现方式,无需手动循环和重复赋值DataFrame,下面是几种实用方法:
1. 递归生成扁平化选择表达式
直接遍历所有嵌套字段,生成一次性展开所有Struct的选择逻辑,还能自定义展开后的字段命名规则:
def flatten_exprs(expr: pl.Expr) -> list[pl.Expr]: if isinstance(expr.dtype, pl.Struct): return [ pl.col(f"{expr.name}.{field}").alias(f"{expr.name}_{field}") for field in expr.dtype.fields ] return [expr] # 生成所有字段的扁平化表达式 flat_exprs = [] for col in df.columns: flat_exprs.extend(flatten_exprs(pl.col(col))) # 生成最终的扁平化DataFrame flat_df = df.select(flat_exprs)
这种方式会把嵌套字段用下划线拼接命名(比如user.address.zip变成user_address_zip),能有效避免字段名冲突。
2. 递归调用unnest处理全层级Struct
写一个递归函数自动识别并展开所有层级的Struct,逻辑清晰且符合函数式风格:
def flatten_df(df: pl.DataFrame) -> pl.DataFrame: struct_cols = [col for col in df if isinstance(df[col].dtype, pl.Struct)] if not struct_cols: return df return flatten_df(df.unnest(struct_cols)) # 直接调用得到结果 flat_df = flatten_df(df)
这个函数会逐层展开所有Struct列,直到DataFrame中不存在任何Struct类型的列为止。
3. 用until函数链式处理(Polars 0.19+)
利用Polars的until方法配合pipe,可以一行代码完成递归展开,完全无显式循环:
from functools import partial # 判断是否还有Struct列 has_struct = lambda df: any(isinstance(dt, pl.Struct) for dt in df.dtypes.values()) # 重复执行unnest直到没有Struct列 flat_df = df.pipe(partial(pl.DataFrame.until, has_struct, lambda df: df.unnest()))
内容的提问来源于stack exchange,提问作者pwb2103
相关产品推荐
相关产品推荐

