如何用Polars原生表达式按条件从指定列填充前置值?
Polars 原生方法实现同组内按count关联前值需求
问题场景
现有如下Polars DataFrame:
df = pl.DataFrame( { 'val': [9, 7, 9, 11, 2, 5], 'count': [1, 2, 1, 2, 1, 2], 'id': [1, 1, 2, 2, 3, 3], } )
需要新增列prev_val,规则是:同一id分组内,取count值减1对应行的val,当count=1时(减1后无对应行)填充null,期望结果如下:
┌─────┬───────┬─────┬──────────┐ │ val ┆ count ┆ id ┆ prev_val │ │ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ i64 ┆ i64 │ ╞═════╪═══════╪═════╪══════════╡ │ 9 ┆ 1 ┆ 1 ┆ null │ │ 7 ┆ 2 ┆ 1 ┆ 9 │ │ 9 ┆ 1 ┆ 2 ┆ null │ │ 11 ┆ 2 ┆ 2 ┆ 9 │ │ 2 ┆ 1 ┆ 3 ┆ null │ │ 5 ┆ 2 ┆ 3 ┆ 2 │ └─────┴───────┴─────┴──────────┘
试过map_rows和UDF,但Polars官方不推荐这类方法,想找原生表达式的实现方式。
原生实现方案
方案1:分组后用shift(适合同组内count按顺序排列的场景)
示例里每个id下的行是按count从小到大排好的,直接对分组后的val列做shift(1)就能得到结果:
df.with_columns( prev_val=pl.col('val').shift(1).over('id') )
方案2:通用关联法(适合count不连续或排序混乱的场景)
如果同组内count不是按顺序排的,或者存在非连续的count值,可以用分组过滤的方式匹配对应值:
df.with_columns( prev_val=pl.col('val') .filter(pl.col('count') == pl.col('count') - 1) .first() .over('id') )
或者用自关联的方式,逻辑更直观:
df.join( df.select(pl.col('id'), pl.col('count').alias('match_count'), pl.col('val').alias('prev_val')) .with_columns(match_count=pl.col('match_count') + 1), left_on=['id', 'count'], right_on=['id', 'match_count'], how='left' ).drop('match_count')
以上都是Polars原生表达式实现,不用依赖UDF或map_rows,性能更符合Polars的设计初衷。
内容的提问来源于stack exchange,提问作者NotAName
相关产品推荐
相关产品推荐

