Polars中如何实现按列分组动态统计指定列的空值占比?
在Polars中实现动态分组统计空值占比的方法
问题描述
我需要在Polars DataFrame中按指定列分组,统计另一组指定列的空值占比。由于DataFrame的列可能会变化,希望能通过传入分组列列表和待统计空值的列列表来动态实现。目前分组可以直接传列列表,但统计空值时只能逐列写代码,写法如下:
df = df.group_by(list_of_grouping_fields)\ .agg( pl.len().alias('Row_Count'), pl.col("INVOICE NUMBER").null_count().alias('INVOICENUMBER_nullcount'), pl.col("ORDER NUMBER").null_count().alias('ORDERNUMBER_nullcount') )
这种写法效率低,列变化时还要修改代码。理想写法是能直接传入列列表和别名列表来动态聚合:
df = df.group_by(list_of_grouping_fields)\ .agg( pl.len().alias('Row_Count'), pl.col([list_of_agg_fields]).null_count().alias([list_of_aliases]) )
请问Polars中有没有方法实现这种动态聚合?
解决方案
Polars支持通过动态生成表达式列表实现这种需求,无需逐列硬编码。可以通过列表推导式生成每个目标列的空值计数和占比表达式,再传入agg()方法。
步骤1:准备数据与参数
先定义分组列、待统计列,以及示例DataFrame:
import polars as pl # 示例数据 df = pl.DataFrame({ "GROUP_COL1": ["A", "A", "B", "B", "A"], "GROUP_COL2": ["X", "Y", "X", "X", "Y"], "INVOICE NUMBER": [123, None, 456, None, 789], "ORDER NUMBER": [None, 987, 654, None, None] }) list_of_grouping_fields = ["GROUP_COL1", "GROUP_COL2"] list_of_agg_fields = ["INVOICE NUMBER", "ORDER NUMBER"]
步骤2:动态生成聚合表达式
利用列表推导式,为每个待统计列生成空值计数、空值占比(空值数/总条数)的表达式,并自定义别名:
# 初始化表达式列表,先加入总行数统计 agg_exprs = [pl.len().alias('Row_Count')] # 为每个目标列添加空值计数和占比表达式 for col in list_of_agg_fields: # 自定义别名规则:去掉空格+小写+后缀 count_alias = col.replace(" ", "").lower() + "_nullcount" ratio_alias = col.replace(" ", "").lower() + "_nullratio" agg_exprs.extend([ pl.col(col).null_count().alias(count_alias), (pl.col(col).null_count() / pl.len()).alias(ratio_alias) ])
步骤3:执行分组聚合
将生成的表达式列表传入agg()方法即可完成动态聚合:
result_df = df.group_by(list_of_grouping_fields).agg(agg_exprs) print(result_df)
输出结果
shape: (3, 7) ┌────────────┬────────────┬───────────┬──────────────────────┬──────────────────────┬─────────────────────┬─────────────────────┐ │ GROUP_COL1 ┆ GROUP_COL2 ┆ Row_Count ┆ invoicenumber_nullco ┆ invoicenumber_nullra ┆ ordernumber_nullcou ┆ ordernumber_nullrat │ │ --- ┆ --- ┆ --- ┆ unt ┆ tio ┆ nt ┆ io │ │ str ┆ str ┆ u32 ┆ --- ┆ --- ┆ --- ┆ --- │ │ ┆ ┆ ┆ u32 ┆ f64 ┆ u32 ┆ f64 │ ╞════════════╪════════════╪═══════════╪══════════════════════╪══════════════════════╪═════════════════════╪═════════════════════╡ │ A ┆ X ┆ 1 ┆ 0 ┆ 0.0 ┆ 1 ┆ 1.0 │ │ A ┆ Y ┆ 2 ┆ 1 ┆ 0.5 ┆ 1 ┆ 0.5 │ │ B ┆ X ┆ 2 ┆ 1 ┆ 0.5 ┆ 1 ┆ 0.5 │ └────────────┴────────────┴───────────┴──────────────────────┴──────────────────────┴─────────────────────┴─────────────────────┘
简化写法
如果不需要复杂的别名规则,也可以用一行代码生成表达式:
agg_exprs = [ pl.len().alias('Row_Count'), *[pl.col(col).null_count().alias(f"{col.replace(' ', '')}_nullcount") for col in list_of_agg_fields], *[(pl.col(col).null_count() / pl.len()).alias(f"{col.replace(' ', '')}_nullratio") for col in list_of_agg_fields] ] result_df = df.group_by(list_of_grouping_fields).agg(agg_exprs)
关键说明
- Polars的
agg()方法接受表达式列表,只要动态生成该列表就能实现动态聚合。 - 别名规则可根据需求自定义,比如保留空格、使用不同后缀等。
- 若仅需要空值计数,去掉占比相关表达式即可。
内容的提问来源于stack exchange,提问作者DixieFlatline
相关产品推荐
相关产品推荐

