如何用Polars处理含异常值的单调递增时序数据差值计算
解决Polars中单调递增数据的异常值平滑问题
针对你遇到的单调递增观测数据异常值处理需求,我们可以通过以下步骤实现目标结果:
核心思路
- 识别异常高点:标记所有
当前值 > 下一个值的位置(这些是不符合单调递增规则的异常高点)。 - 修正异常值:
- 若异常点是第一个元素,将其修正为
下一个值 / 2(实现和下一个值的平均拆分)。 - 若异常点不是第一个元素,将其修正为
(前一个值 + 下一个值) / 2(保证前后累计值的平滑过渡)。
- 若异常点是第一个元素,将其修正为
- 计算分钟增量:基于修正后的累计值,计算每分钟的增量(第一个增量为修正后的初始值,后续为当前值与前一个值的差值)。
完整实现代码
import polars as pl # 示例数据 df = pl.DataFrame(dict( time= ['10:00', '10:01', '10:02', '10:03', '10:04', '10:05', '10:06'], value=[ 1000 , 10 , 22 , 22 , 50 , 1100 , 60 ] )) # 处理异常值并计算目标增量 result_df = df.with_columns( # 标记异常高点:当前值大于下一个值 is_anomaly=pl.col('value').shift(-1) < pl.col('value'), # 获取下一个值和前一个值,用于修正异常 next_value=pl.col('value').shift(-1), prev_value=pl.col('value').shift() ).with_columns( # 生成修正后的累计值 corrected=pl.when(pl.col('is_anomaly')) # 第一个元素异常时,取下一个值的一半 .then(pl.when(pl.col('prev_value').is_null()) .then(pl.col('next_value') / 2) # 非第一个元素异常时,取前后值的平均值 .otherwise((pl.col('prev_value') + pl.col('next_value')) / 2)) # 非异常值保持原数据 .otherwise(pl.col('value')) ).with_columns( # 计算每分钟增量:第一个值用修正后的初始值填充,后续用差值 increment=pl.col('corrected').diff().fill_null(pl.col('corrected')) ) # 查看结果 print(result_df.select('time', 'value', 'corrected', 'increment'))
输出结果
运行代码后,increment列即为你需要的目标结果:[5, 5, 12, 0, 28, 5, 5],对应输出如下:
shape: (7, 4) ┌────────┬───────┬──────────┬──────────┐ │ time ┆ value ┆ corrected ┆ increment│ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ f64 ┆ f64 │ ╞════════╪═══════╪═══════════╪══════════╡ │ 10:00 ┆ 1000 ┆ 5.0 ┆ 5.0 │ │ 10:01 ┆ 10 ┆ 10.0 ┆ 5.0 │ │ 10:02 ┆ 22 ┆ 22.0 ┆ 12.0 │ │ 10:03 ┆ 22 ┆ 22.0 ┆ 0.0 │ │ 10:04 ┆ 50 ┆ 50.0 ┆ 28.0 │ │ 10:05 ┆ 1100 ┆ 55.0 ┆ 5.0 │ │ 10:06 ┆ 60 ┆ 60.0 ┆ 5.0 │ └────────┴───────┴───────────┴──────────┘
原代码问题分析
你之前的代码先将异常值设为0再尝试替换,但第一个异常点的shift()结果为null,导致修正后出现空值;同时diff()默认会让第一个增量为null,最终缺失前两个有效增量。通过直接修正异常点为合理的累计值,并填充第一个增量的空值,就能解决这些问题。
内容的提问来源于stack exchange,提问作者char101
相关产品推荐
相关产品推荐

