使用R中的data.table根据条件合并两行的值
在一个数据集中,我有一个活动、开始和停止时间以及一个id,我希望合并同一列中两行的值,并在几个条件适用时更新其他列。 首先是一个数据示例:使用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",
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