Polars中如何删除某列同值分组内的无效数据行(当分组存在有效数据时)
Polars中如何删除某列同值分组内的无效数据行(当分组存在有效数据时)
嘿,我来帮你搞定这个分组过滤的问题!先理清楚你的需求:你有一个按name分组的DataFrame,对于每个分组,如果里面存在found='yes'的有效行,就只保留这个有效行,把同组里found='no'的无效行删掉;如果整个分组里全是无效行(比如name='b'的组),那就把这个组的所有行都保留下来,对吧?
先看看你给出的原始数据,用代码还原一下:
import polars as pl df = pl.DataFrame({ 'name': ['a', 'a', 'b', 'b'], 'found': ['yes', 'no', 'no', 'no'], 'found_in_iteration': ['1', 'not_found', 'not_found', 'not_found'] })
接下来给你两种靠谱的解决方法,你可以根据自己的习惯选:
方法一:用窗口函数(性能优先)
这种方法用Polars的窗口函数做向量化操作,大数据量下速度更快,代码也简洁:
result = df.filter( # 保留本身是有效行的记录 pl.col('found') == 'yes' # 或者,当前分组没有任何有效行时,保留所有行 | ~pl.col('found').eq('yes').any().over('name') )
运行后得到的结果是:
shape: (3, 3) ┌──────┬───────┬────────────────────┐ │ name ┆ found ┆ found_in_iteration │ │ --- ┆ --- ┆ --- │ │ str ┆ str ┆ str │ ╞══════╪═══════╪════════════════════╡ │ a ┆ yes ┆ 1 │ │ b ┆ no ┆ not_found │ │ b ┆ no ┆ not_found │ └──────┴───────┴────────────────────┘
给你拆解下逻辑:
pl.col('found').eq('yes').any().over('name'):这部分会给每个name分组标记一个布尔值——如果组里有至少一个found='yes'的行,就返回True,否则False,而且组里的每一行都会带上这个标记。- 过滤条件就很清晰了:要么行本身是有效行,要么该组没有任何有效行,这两种情况我们都保留。
方法二:分组后单独处理(直观易懂)
如果你觉得窗口函数有点绕,也可以用分组后逐个处理的方式,逻辑更直白:
result = df.group_by('name').map( lambda group: # 如果当前组有有效行,就只保留有效行 group.filter(pl.col('found') == 'yes') # 否则直接返回整个组 if group['found'].eq('yes').any() else group )
这个方法就是把每个分组单独拎出来判断:如果组里有有效行,就过滤出有效行;如果全是无效行,就原封不动保留整个组,最终再把所有分组合并起来。
两种方法都能得到你想要的结果,大数据量的话更推荐第一种窗口函数的方法,性能会更好哦!
备注:内容来源于stack exchange,提问作者gernophil
相关产品推荐
相关产品推荐

