首页 > 解决方案 > 根据班级保持时间顺序折叠常规时间段数据

问题描述

这个问题与我之前在以下链接中的帖子密切相关: 将时间段扩展到定期出现的时间戳

本质上,这是该问题的相反步骤。

我现在有一个定期间隔的数据集(1 分钟周期),我需要折叠这些周期,以便每一行代表一个类保持不变的时间段,如下所示:

在此处输入图像描述

示例输入数据框是:

df_in <- tibble(st =seq(ymd_hms("2016-01-01 00:35:00"),
                         ymd_hms("2016-01-01 00:58:00")-60,60),
                 en = st+59)
df_in$cl <- c("a",rep("c",3),rep("a",6),rep("c",9),rep("a",1),"c",rep("b",2))

我设法通过如下代码所示的循环来完成此操作,但这非常低效且速度慢(我的数据源在数百万行中)。我确信有一种通过 dplyr 执行此操作的 Verctorized 方式,我希望有人能指出我正确的方向:

df_in$flag <- 1
df_in %>% 
  mutate(flag = ifelse(lag(cl)==cl,0,1)) -> df_in

df_in$flag[1] <- 1
df_in$flag2 <- 0
df_in$flag2[1] <- 1

for (i in 2:nrow(df_in)) {
  if (df_in$flag[i] == 0) {
    df_in$flag2[i] = df_in$flag2[i-1]
  } else {
    df_in$flag2[i] = df_in$flag2[i-1] + 1
  }
}

df_in %>% 
  group_by(flag2) %>%
  summarise(st = min(st),
            en = max(en),
            cl = unique(cl)) %>% 
View()

再次提前感谢...

标签: rdplyrtimestampvectorization

解决方案


这是使用的一个选项data.table

library(data.table)
setDT(df_in)[, .(st = min(st), en = max(en)), by = .(cl, idx = rleid(cl))]
#   cl idx                  st                  en
#1:  a   1 2016-01-01 00:35:00 2016-01-01 00:35:59
#2:  c   2 2016-01-01 00:36:00 2016-01-01 00:38:59
#3:  a   3 2016-01-01 00:39:00 2016-01-01 00:44:59
#4:  c   4 2016-01-01 00:45:00 2016-01-01 00:53:59
#5:  a   5 2016-01-01 00:54:00 2016-01-01 00:54:59
#6:  c   6 2016-01-01 00:55:00 2016-01-01 00:55:59
#7:  b   7 2016-01-01 00:56:00 2016-01-01 00:57:59

我们设置st等于min(st)en等于max(en)byclidx = rleid(cl)rleid创建一个“运行长度类型 id 列”。


dplyr你一起做

library(dplyr)
df_in %>% 
  mutate(idx = data.table::rleid(cl)) %>% 
  group_by(cl, idx) %>% 
  summarise(st = min(st),
            en = max(en)) %>% 
  arrange(idx) %>% 
  select(-idx)

推荐阅读