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

基于16小时步长筛选时间差DataFrame的R语言技术求助

16小时步长DataFrame筛选方案实现

需求说明

我有一个包含diff_h列(存储当前行与前一行的小时时间差)的DataFrame,行是连续序列。需筛选出构成16小时规则步长的行,删除非16小时步长的中间行,规则如下:

  • NA会中断累计(如8、NA、8无法凑成16)
  • 无法凑成16的4/8小时差需设为NA

此前提供的代码仅保留少量有效步长,现给出输入示例、现有代码及期望输出,寻求正确实现方案。

输入示例

ID      Datetime        diff_h
134_18  7/27/2018 0:00  NA
134_18  7/27/2018 19:00 19
134_18  7/28/2018 0:00  5
134_18  7/28/2018 8:00  8
134_18  7/28/2018 16:00 8
134_18  7/29/2018 0:00  8
134_18  7/29/2018 8:00  8
134_18  7/29/2018 12:00 4
134_18  7/30/2018 16:00 4
134_18  7/30/2018 20:00 4
134_18  7/30/2018 16:00 8
134_18  7/31/2018 0:00  8
134_18  7/31/2018 8:00  8
134_18  7/31/2018 16:00 8
134_18  8/1/2018 8:00   16
134_18  8/1/2018 16:00  8
134_18  8/2/2018 0:00   8
134_18  8/2/2018 8:00   8
134_18  8/2/2018 16:00  8

现有代码及问题

现有代码(已删除报错的%>% select(-grp) %>%):

data1 <- test %>% 
  group_by(ID, grp = rleid(diff_h %/% 16)) %>% 
  mutate(diff_h = cumsum(diff_h), 
         diff_h = replace(diff_h, n() ==1 & diff_h != 16, NA_real_))  %>% 
  ungroup %>%
  filter(diff_h == 16|is.na(diff_h))

现有输出仅保留了少量有效步长,不符合需求:

134_18  7/27/2018 0:00  NA  1
134_18  7/27/2018 19:00 NA  2
134_18  8/1/2018 8:00   16  4
134_18  8/2/2018 0:00   16  5

期望输出

ID  Datetime    diff_h
134_18  7/27/2018 0:00  NA
134_18  7/27/2018 19:00 NA
134_18  7/28/2018 0:00  NA
134_18  7/28/2018 16:00 16
134_18  7/29/2018 8:00  16
134_18  7/29/2018 12:00 NA
134_18  7/30/2018 16:00 16
134_18  7/31/2018 8:00  16
134_18  7/31/2018 16:00 NA
134_18  8/1/2018 8:00   16
134_18  8/2/2018 0:00   16
134_18  8/2/2018 16:00  16

正确实现方案

使用dplyr结合data.table的rleid函数,按规则分组累计并筛选:

library(dplyr)
library(data.table)

result <- test %>%
  # 按ID分组,同时用rleid标记NA中断的连续组
  group_by(ID, grp = rleid(is.na(diff_h))) %>%
  mutate(
    # 计算每组内的累计小时差(NA行不计入累计)
    cum_diff = cumsum(ifelse(is.na(diff_h), 0, diff_h)),
    # 标记累计差刚好达到16倍数的行
    is_16_step = cum_diff %in% seq(16, max(cum_diff, na.rm = TRUE), 16),
    # 生成最终的diff_h列
    new_diff_h = case_when(
      # NA行保持NA
      is.na(diff_h) ~ NA_real_,
      # 凑成16的行设为16
      is_16_step ~ 16,
      # 每组最后一行若无法凑成16,设为NA
      row_number() == n() & (cum_diff %% 16) != 0 ~ NA_real_,
      # 其他中间行标记为待删除
      TRUE ~ NA_real_
    ),
    # 标记需要保留的行:NA行、16步长节点、每组最后无法凑成的行
    keep = is.na(diff_h) | is_16_step | (row_number() == n() & (cum_diff %% 16) != 0)
  ) %>%
  ungroup() %>%
  # 过滤保留目标行
  filter(keep) %>%
  # 选择需要的列并重命名
  select(ID, Datetime, diff_h = new_diff_h)

代码逻辑说明

  1. 分组规则:用rleid(is.na(diff_h))确保NA会中断累计分组,每组内是连续的非NA时间差序列。
  2. 累计计算:cum_diff计算每组内的累计小时差,NA行不参与累计。
  3. 步长标记:is_16_step定位累计差刚好达到16的倍数的行,这些行就是16小时步长的节点。
  4. 值处理:new_diff_h按规则赋值:NA行保留NA,16步长节点设为16,每组最后无法凑成16的行设为NA。
  5. 行筛选:keep标记需要保留的行,过滤后得到符合期望的结果。

内容的提问来源于stack exchange,提问作者Beardedant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:09:23