使用R中的data.table根据条件合并两行的值

使用R中的data.table根据条件合并两行的值,r,data.table,event-log,R,Data.table,Event Log,在一个数据集中,我有一个活动、开始和停止时间以及一个id,我希望合并同一列中两行的值,并在几个条件适用时更新其他列。 首先是一个数据示例: library(data.table) DT <- data.table(person=c(1,1,1,1,2,2,2,2,2,3,3,3,3), activity=c("grab", "walk", "remove", "delete", "run", "talk", "walk", "remove",

在一个数据集中,我有一个活动、开始和停止时间以及一个id,我希望合并同一列中两行的值,并在几个条件适用时更新其他列。 首先是一个数据示例:

library(data.table)
DT <- data.table(person=c(1,1,1,1,2,2,2,2,2,3,3,3,3),
             activity=c("grab", "walk", "remove", "delete", "run", "talk", "walk", "remove",
                        "grab", "walk", "delete", "talk", "remove"),
             start_time=c(0,1,3,6,0,2,2,3,3,3,6,6,7), stop_time=c(1,3,5,7,1,4,4,8,4,5,7,7,8))
 DT
我想更新开始和停止时间,并合并每个人的“活动”列,如果:

这些活动是并行进行的。具体而言,如果以下活动的开始时间早于该人员的前一活动的停止时间。或: 如果一个人的活动开始或停止时间相同。 更新的行应反映组合活动的开始和停止时间,除更新的行外,应删除所有行。以下是我希望通过提供的数据示例实现的目标:

DT.goal <- data.table(person=c(1,1,2,2,3,3),
                  activity=c("grab + walk + remove", "delete", "run", "talk + walk + grab + remove",
                             "walk", "delete + talk + remove"),
                  start_time=c(0,6,0,2,3,6), stop_time=c(5,7,1,8,5,8))
DT.goal
到目前为止,我提出了以下不完整的尝试:

DT.test <- DT[start_time <= shift(stop_time, 1L, type="lag"), 
          cond := T, by=person]
DT.test <- DT.test[cond==T, 
          new_activity := paste(activity, shift(activity, 1L, type="lag")), by=person]
DT.test <- DT.test[, new_start := start_time, by=person][cond==T, new_start := min(start_time), by=person]
DT.test <- DT.test[, new_stop := stop_time, by=person][cond==T, new_stop := max(stop_time), by=person]
但是,对于每个人来说,使用shift,type=lag对于第一行不是很有用,因为它没有要查看的前一行。此外,如果条件评估结果不为真,则粘贴NA


有人能帮我上路吗?

请检查以下内容:

library(data.table)
DT <- data.table(person=c(1,1,1,1,2,2,2,2,2,3,3,3,3),
                 activity=c("grab", "walk", "remove", "delete", "run", "talk", "walk", "remove",
                            "grab", "walk", "delete", "talk", "remove"),
                 start_time=c(0,1,3,6,0,2,2,3,3,3,6,6,7), stop_time=c(1,3,5,7,1,4,4,8,4,5,7,7,8))

setorder(DT, person, start_time)
DT[, concatenate := start_time %in% stop_time | stop_time %in% start_time | duplicated(start_time) | duplicated(start_time, fromLast=TRUE), by = "person"]
DT[, concatenate_grp := rleid(concatenate), by = "person"]
DT[, paste(activity, collapse = " + "), by = c("person", "concatenate_grp")]
DT.goal <- DT[, .(activity = paste(activity, collapse = " + "), start_time = min(start_time), stop_time = max(stop_time)), by = c("person", "concatenate_grp")][, concatenate_grp := NULL]
使用dplyr,我们按人和开始和停止时间排列数据。我们为每个人创建一个时间重叠的组,在每个组中选择第一个开始时间和最后一个停止时间,并连接每个组中的所有活动

library(dplyr)

DT %>%
  arrange(person, start_time, stop_time) %>%
  group_by(person, group = cumsum(start_time > 
                lag(stop_time, default = first(stop_time)))) %>%
  summarise(start_time = first(start_time), 
            stop_time = last(stop_time), 
            activity = paste(activity, collapse = " + ")) %>%
  select(-group)

#  person start_time stop_time activity                   
#   <dbl>      <dbl>     <dbl> <chr>                      
#1      1          0         5 grab + walk + remove       
#2      1          6         7 delete                     
#3      2          0         1 run                        
#4      2          2         8 talk + walk + grab + remove
#5      3          3         5 walk                       
#6      3          6         8 delete + talk + remove     

另一个选择是借用David Aurenburg的解决方案,从

输出:

   person g                    activity start_time stop_time
1:      1 0        grab + walk + remove          0         5
2:      1 1                      delete          6         7
3:      2 0                         run          0         1
4:      2 1 talk + walk + grab + remove          2         8
5:      3 0                        walk          3         5
6:      3 1      delete + talk + remove          6         8

数据是否按默认顺序排列?不,不是。人是没有顺序的,每个人的活动也不是按时间顺序排列的。这很有效。如何按字母顺序排列每个活动?@UTq对活动进行排序。在摘要中使用activity=pastesortactivity,collapse=+这在我提供的示例数据中有效,但考虑到我的实际开始和停止时间是POSIXt,显示以下错误:“cummax”未为POSIXt对象定义。可能有帮助吗?
setorder(DT, person, stop_time)
DT[, 
   break_here := start_time > shift(stop_time, 1, stop_time[1]) , 
   by = person
   ][, 
     .(activity = paste(activity, collapse = " + "), start_time = start_time[1], stop_time = stop_time[.N]), 
     keyby = .(person, helper_var = cumsum(break_here))
     ][, !"helper_var"]


   person                    activity start_time stop_time
1:      1        grab + walk + remove          0         5
2:      1                      delete          6         7
3:      2                         run          0         1
4:      2 talk + walk + grab + remove          2         8
5:      3                        walk          3         5
6:      3      delete + talk + remove          6         8
setorder(DT, person, start_time, stop_time)
DT[, g := c(0L, cumsum(shift(start_time, -1L) > cummax(stop_time))[-.N]), person]
DT[, .(activity=paste(activity, collapse=" + "), 
        start_time=min(start_time), stop_time=max(stop_time)), 
    .(person, g)]
   person g                    activity start_time stop_time
1:      1 0        grab + walk + remove          0         5
2:      1 1                      delete          6         7
3:      2 0                         run          0         1
4:      2 1 talk + walk + grab + remove          2         8
5:      3 0                        walk          3         5
6:      3 1      delete + talk + remove          6         8