在Polars中使用diff或shift时如何忽略前置空值?
分组内计算当前值与前一个非空值的差值
需求是在分组内,计算当前值与前一个非空值的差值。从id和value列出发,想要生成result列,示例如下:
| id | value | result | 说明 |
|---|---|---|---|
| a | 10 | null | 10 - 无前置非空值 |
| a | null | null | null 与前置值无法计算差值 |
| a | 30 | 20 | 30 - 10 |
| b | 5 | null | 5 - 无前置非空值 |
| b | 10 | 5 | 10 - 5 |
| b | null | null | null 与前置值无法计算差值 |
| b | null | null | null 与前置值无法计算差值 |
| b | 40 | 30 | 40 - 10 |
背景说明
这是填充空值的中间步骤,最终目标是填充空值,但并非线性填充——因为每行带有时间戳,需要根据行之间的时间差分配两个非空值的差值。例如,对于"a"分组:第一行与第二行时间差为10秒,第二行与第三行时间差为30秒,那么差值20应分配为:第二行填充值为10 + 20*(10/40),第三行填充值为10 + 20*(30/40)。
尝试的代码及问题
最初在Polars中尝试以下代码:
import polars as pl df = pl.DataFrame({ "id": ["a", "a", "a", "b", "b", "b", "b", "b"], "value": [10, None, 30, 5, 10, None, None, 40] }) df_delta = df.with_columns( delta = pl.col("value").diff(1).over("id"), delta_ignore = pl.col("value").diff(1, null_behavior="ignore").over("id") )
其中第二列使用了null_behavior="ignore"参数,但得到的结果不符合预期:
| id | value | delta | delta_ignore |
|---|---|---|---|
| a | 10 | null | null |
| a | null | null | null |
| a | 30 | null | null |
| b | 5 | null | null |
| b | 10 | 5 | 5 |
| b | null | null | null |
| b | null | null | null |
| b | 40 | null | null |
解决方法
通过扩展窗口分区的方法解决了问题,代码如下:
df.with_columns( delta = pl.col("value").diff(1).over("id", pl.col("value").is_not_null()) )
得到的结果符合预期:
| id | value | delta |
|---|---|---|
| a | 10 | null |
| a | null | null |
| a | 30 | 20 |
| b | 5 | null |
| b | 10 | 5 |
| b | null | null |
| b | null | null |
| b | 40 | 30 |
内容的提问来源于stack exchange,提问作者Wouter De Raeve
相关产品推荐
相关产品推荐

