如何在Polars中对分组非规整时间序列的列执行基于时间的偏移并生成目标列
如何在Polars中对分组非规整时间序列的列执行基于时间的偏移并生成目标列
嗨,我来帮你搞定这个Polars的时间序列问题!你说的是按id分组的非规整时间序列,要用with_columns生成目标的result列对吧?刚好我对这个场景熟得很~
首先得明确:非规整时间序列的核心是同一个id下的日期间隔不固定,不能直接用普通的shift(那是按行偏移,不管时间差),得结合分组和时间排序/滚动窗口来处理。我先补全你没写完的示例数据(猜你应该有date和值列,比如value),方便后续演示:
import datetime as dt import polars as pl df = pl.DataFrame( { "id": ["1", "1", "1", "2", "2", "2"], "date": [ dt.date(2023, 1, 1), dt.date(2023, 1, 3), # 非规整间隔:2天 dt.date(2023, 1, 6), # 非规整间隔:3天 dt.date(2023, 1, 2), dt.date(2023, 1, 5), dt.date(2023, 1, 7), ], "value": [10, 20, 30, 40, 50, 60] } )
接下来分两种最常见的场景给你对应的实现代码,都能用with_columns完成:
场景1:取同分组内上一个时间点的对应值
这种情况只要先在分组内按日期排序,再用shift(1)偏移就行,直接把逻辑写在with_columns里:
# 先按id和date排序,再生成result列 df_result = df.sort(["id", "date"]).with_columns( result=pl.col("value").shift(1).over("id") )
这里的over("id")指定按分组处理,shift(1)会在每个分组内的有序行里取上一行的value——因为我们先按日期排过序了,完全适配非规整时间序列的情况。
场景2:取同分组内当前日期前N天内的对应值
如果你的需求是基于时间间隔(比如取当前日期往前5天内的最后一个值),那用Polars的rolling滚动窗口,同样可以嵌套在with_columns里:
df_result = df.with_columns( result=pl.col("value").rolling( index="date", # 指定作为时间索引的列 period="5d", # 时间窗口范围:当前日期往前推5天 by="id", # 按id分组处理每个窗口 closed="left" # 窗口不包含当前日期本身,可根据需求调整 ).last() # 取窗口内的最后一个值,也可以换成sum()/mean()等聚合逻辑 )
这个方法完全不依赖行的顺序,直接按实际时间间隔筛选数据,是非规整时间序列的绝佳解决方案。
比如场景1的最终输出会是这样的:
shape: (6, 4) ┌─────┬────────────┬───────┬────────┐ │ id ┆ date ┆ value ┆ result │ │ --- ┆ --- ┆ --- ┆ --- │ │ str ┆ date ┆ i64 ┆ i64 │ ╞═════╪════════════╪═══════╪════════╡ │ 1 ┆ 2023-01-01 ┆ 10 ┆ null │ │ 1 ┆ 2023-01-03 ┆ 20 ┆ 10 │ │ 1 ┆ 2023-01-06 ┆ 30 ┆ 20 │ │ 2 ┆ 2023-01-02 ┆ 40 ┆ null │ │ 2 ┆ 2023-01-05 ┆ 50 ┆ 40 │ │ 2 ┆ 2023-01-07 ┆ 60 ┆ 50 │ └─────┴────────────┴───────┴────────┘
备注:内容来源于stack exchange,提问作者yz_jc
相关产品推荐
相关产品推荐

