我想根据极坐标数据框中的某个条件增加一列值,同时考虑满足该条件的次数。
示例数据。
import polars as pl
df = pl.DataFrame({
"before": [0, 0, 0, 0, 0, 0, 0, 0, 0],
"cdl_type": ["REC", "REC", "GEC", None, None, "GEC", None, "REC", "GEC"],
})
当前的方法。
df = df.with_columns(
a=(
pl.when(pl.col("cdl_type").is_in(["GEC", "REC"])).then(
pl.int_ranges(
pl.col("cdl_type")
.is_in(["REC", "GEC"])
.rle()
.struct.field("len")
).flatten()
)
.when(pl.col('cdl_type').is_null().and_(pl.col('cdl_type').shift(1).is_not_null()))
.then(pl.lit(1))
.otherwise(0)
)
)
预期输出。
┌────────┬──────────┬───────┐
│ before ┆ cdl_type ┆ after │
│ --- ┆ --- ┆ --- │
│ i64 ┆ str ┆ i64 │
╞════════╪══════════╪═══════╡
│ 0 ┆ REC ┆ 0 │
│ 0 ┆ REC ┆ 1 │
│ 0 ┆ GEC ┆ 2 │
│ 0 ┆ null ┆ 3 │
│ 0 ┆ null ┆ 0 │
│ 0 ┆ GEC ┆ 0 │
│ 0 ┆ null ┆ 1 │
│ 0 ┆ REC ┆ 0 │
│ 0 ┆ GEC ┆ 1 │
└────────┴──────────┴───────┘
根据当前的方法和预期的结果,我认为条件是
cdcl_type
等于"REC"
或"GEC"
。预期输出可以通过以下方式获得。
pl.Expr.rle_id
条件表达式获取相应的 id。pl.int_range
。(免责声明:我之前写过这篇文章并发布它 - 刚刚意识到它与@Hericks 的回答有多么相似)。
由于您希望每次连续的“REC”或“GEC”组中断时重置计数,因此您需要将这个问题分成两部分。将逻辑重写为伪代码,您最终会得到:
"REC"
或"GEC"
...一旦我们完成了这个逻辑,我们应该能够将所有内容向下移动一行来创建您想要的输出。
我们将
null
在样本框中添加额外的一行(以帮助验证结果)。(我最初的答案产生了所提供样本的预期输出,但对于长度 > 2 的 None 运行却不起作用)
看起来您还想将第一个后续空值作为运行长度的一部分- 这可以通过 前向填充1 步来完成。
rle()
给出一个包含每个 {len,value} 的结构这些
len
值被赋予int_ranges()
并被展平以创建计数列。然后我们将剩余的空值设置回 0
采用这种方法的原因是它避免使用
.over()
- 并且如果处理更大的数据框会产生更快的结果。