Python Polars分组时如何忽略空值/NULL值列?
问题描述
现有如下Polars DataFrame:
df = pl.DataFrame({ 'last_name':['James','Warner','Marino','James','Warner','Marino','James'], 'first_name':['Horn','Bro','Kach','Horn','Bro','Kach','Horn'], 'dob':['03/06/1990','09/16/1990','03/06/1990','','03/06/1990','',''] })
对last_name、first_name和dob列分组统计数量:
df.group_by('last_name','first_name','dob').len()
得到结果:
shape: (6, 4) ┌───────────┬────────────┬────────────┬─────┐ │ last_name ┆ first_name ┆ dob ┆ len │ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ str ┆ str ┆ u32 │ ╞═══════════╪════════════╪════════════╪═════╡ │ Warner ┆ Bro ┆ 09/16/1990 ┆ 1 │ │ Marino ┆ Kach ┆ 03/06/1990 ┆ 1 │ │ Marino ┆ Kach ┆ ┆ 1 │ │ James ┆ Horn ┆ ┆ 2 │ # 不符合预期 │ James ┆ Horn ┆ 03/06/1990 ┆ 1 │ │ Warner ┆ Bro ┆ 03/06/1990 ┆ 1 │ └───────────┴────────────┴────────────┴─────┘
需求是分组时忽略分组列中的空值/空字符串,比如James Horn的两条空dob记录不应被纳入分组,预期输出:
shape: (4, 4) ┌───────────┬────────────┬────────────┬─────┐ │ last_name ┆ first_name ┆ dob ┆ len │ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ str ┆ str ┆ u32 │ ╞═══════════╪════════════╪════════════╪═════╡ │ Warner ┆ Bro ┆ 03/06/1990 ┆ 1 │ │ James ┆ Horn ┆ 03/06/1990 ┆ 1 │ │ Marino ┆ Kach ┆ 03/06/1990 ┆ 1 │ │ Warner ┆ Bro ┆ 09/16/1990 ┆ 1 │ └───────────┴────────────┴────────────┴─────┘
目前可以通过先过滤再分组实现:
df.filter(pl.col.dob != '').group_by('last_name','first_name','dob').len()
但如果有10个分组列需要过滤,手动逐个编写条件会很繁琐,有没有更简便的方案?
解决方案
方法1:批量过滤所有分组列的空字符串
先定义分组列的列表,再用pl.all批量生成过滤条件,确保所有分组列都不为空字符串:
group_cols = ['last_name', 'first_name', 'dob'] df.filter(pl.all(group_cols) != '').group_by(group_cols).len()
如果你的空值是Polars原生的null(而非空字符串),可以改用is_not_null():
df.filter(pl.all(group_cols).is_not_null()).group_by(group_cols).len()
方法2:统一转换空值后批量删除
先把分组列中的空字符串转为null,再一次性删除包含null的行,最后分组统计:
group_cols = ['last_name', 'first_name', 'dob'] (df.with_columns(pl.col(group_cols).str.strip().replace('', None)) .drop_nulls(subset=group_cols) .group_by(group_cols) .len())
这里的str.strip()用于处理可能存在的空白字符串(比如' '),如果确定没有这类情况可以省略。
方法3:分组后过滤(效率较低,不推荐)
如果不想提前过滤,也可以先完成分组统计,再过滤掉包含空字符串的分组结果,但这种方式会先对所有行分组,再做过滤,效率不如提前过滤:
(df.group_by('last_name','first_name','dob').len() .filter(pl.all(['last_name','first_name','dob']) != ''))
内容的提问来源于stack exchange,提问作者myamulla_ciencia
相关产品推荐
相关产品推荐

