You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在R中追踪data.table时间序列数据的非零值变化

高效实现data.table分组追踪上一次非零值的时间差

这是个很常见的分组状态追踪需求,用data.table的原生矢量化操作就能高效搞定,完全不用写循环,性能拉满~

实现思路

核心逻辑拆解成三步:

  • 按id分组后,先标记出每个value列非零位置对应的time,其余位置设为NA
  • 用**向前填充(last observation carried forward)**把NA替换成最近一次非零值的time
  • 最后用当前行的time减去填充后的时间,得到上一次非零到当前的间隔;如果从未出现非零值,就保留NA

完整代码

library(data.table)

# 构造原始数据
df = data.table(
  id = c(rep(1, 3), rep(2, 4), rep(3, 2)),
  time = c(seq(1, 3, 1), seq(1, 4, 1), seq(3, 4)),
  value1 = c(0, 0, 0, 0, 2, 0, 0, 0, 1),
  value2 = c(0, 1, 0, 1, 0, 0, 0, 0, 1)
)

# 定义复用函数,避免重复代码
get_last_change = function(val_col, time_col) {
  # 标记非零值对应的时间
  temp_times = fifelse(val_col != 0, time_col, NA_real_)
  # 向前填充最近的非零时间
  filled_times = nafill(temp_times, type = "locf")
  # 计算当前时间与最近非零时间的差,无则返回NA
  fifelse(is.na(filled_times), NA_real_, time_col - filled_times)
}

# 分组计算新增列
df[, `:=`(
  last_change1 = get_last_change(value1, time),
  last_change2 = get_last_change(value2, time)
), by = id]

# 调整列顺序匹配期望结果
setcolorder(df, c("id", "time", "value1", "last_change1", "value2", "last_change2"))

# 查看结果
print(df)

运行结果

id time value1 last_change1 value2 last_change2
1:  1    1      0           NA      0           NA
2:  1    2      0           NA      1            0
3:  1    3      0           NA      0            1
4:  2    1      0           NA      1            0
5:  2    2      2            0      0            1
6:  2    3      0            1      0            2
7:  2    4      0            2      0            3
8:  3    3      0           NA      0           NA
9:  3    4      1            0      1            0

为什么这个方案高效?

  • 全程用data.table的矢量化函数(fifelse、nafill),底层是C优化的,比循环/apply类方法快几个数量级
  • 分组操作是data.table的强项,内存使用更高效,适合处理百万级以上的大表
  • 封装函数后,新增更多valueN列时只需一行代码,扩展性极强

内容的提问来源于stack exchange,提问作者mr.bjerre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:41:28