基于累计器状态重置的运行计数变量实现问题求助
问题:计算燃气流量累计值的连续未变化时长(gap_length)
我有一个以15分钟为间隔、跟踪燃气流量累计值的时间序列数据集,示例如下:
Date Time engine_totalizer 12/25/2021 9:30:00 187304950 12/25/2021 9:15:00 187304854 12/25/2021 9:00:00 187304854 12/25/2021 8:45:00 187304854 12/25/2021 8:30:00 187304854 12/25/2021 8:15:00 187304854 12/25/2021 8:00:00 187304854 12/25/2021 7:45:00 187304854 12/25/2021 7:30:00 187304854 12/25/2021 7:15:00 187304854 12/25/2021 7:00:00 187304854
其中engine_totalizer字段会周期性“卡住”(如7:00:00-9:15:00时段数值未变化)。需要创建gap_length变量:
- 当累计值在相邻时间戳间变化时,
gap_length为0; - 当累计值连续未变化时,从0开始递增计数(目标效果如下):
Date Time engine_totalizer gap_length 12/25/2021 9:30:00 187304950 0 12/25/2021 9:15:00 187304854 10 12/25/2021 9:00:00 187304854 9 12/25/2021 8:45:00 187304854 8 12/25/2021 8:30:00 187304854 7 12/25/2021 8:15:00 187304854 6 12/25/2021 8:00:00 187304854 5 12/25/2021 7:45:00 187304854 4 12/25/2021 7:30:00 187304854 3 12/25/2021 7:15:00 187304854 2 12/25/2021 7:00:00 187304854 1 12/25/2021 6:45:00 187304700 0
我尝试用dplyr的case_when和lead函数实现,但结果中gap_length全为0:
# Initialize gap_length df$gap_length <- 0 df<-df%>% mutate(gap_length = case_when(engine_totalizer == lead(engine_totalizer) ~ lead(gap_length) + 1, TRUE ~ 0))
求正确实现方式。
解决方案
你的代码失效原因是**lead(gap_length)引用的是未更新的初始值(全0)**,导致计算结果始终为0。要实现目标需求,需要先标记连续相同值的区块,再在区块内倒序生成计数。
正确代码实现
library(dplyr) # 第一步:确保数据按时间降序排列(匹配示例的顺序) df <- df %>% mutate(datetime = as.POSIXct(paste(Date, Time), format = "%m/%d/%Y %H:%M:%S")) %>% arrange(desc(datetime)) %>% select(-datetime) # 可选:移除临时生成的datetime列 # 第二步:计算gap_length df <- df %>% # 生成连续相同engine_totalizer的分组ID mutate(group_id = cumsum(engine_totalizer != lag(engine_totalizer, default = first(engine_totalizer) + 1))) %>% group_by(group_id) %>% # 组内第一行(值变化的位置)为0,后续行依次递增 mutate(gap_length = row_number() - 1) %>% ungroup() %>% select(-group_id) # 移除临时分组ID列
关键逻辑说明
- 分组标识
group_id:通过cumsum(engine_totalizer != lag(...)),每当engine_totalizer发生变化时,分组ID自动加1,把连续相同值的行归为同一组; - 倒序计数:在每个分组内,
row_number() - 1让组内第一行(最新的、值刚变化的行)为0,时间更早的行依次递增,完全匹配目标效果; - 默认值处理:
lag(..., default = first(engine_totalizer) + 1)确保第一行能正确生成第一个分组ID,避免逻辑错误。
如果你的原始数据是按时间升序排列的,只需将arrange(desc(datetime))改为arrange(datetime),并将gap_length = row_number() - 1替换为gap_length = n() - row_number(),即可实现从变化点往前递增的计数。
内容的提问来源于stack exchange,提问作者Bryan Stolzenburg
相关产品推荐
相关产品推荐

