我有一个原始数据框,看起来像这样:
test
id class time
1 1 start 2019-06-20 00:00:00
2 1 end 2019-06-20 00:05:00
3 1 start 2019-06-20 00:10:00
4 1 end 2019-06-20 00:15:00
5 2 end 2019-06-20 00:20:00
6 2 start 2019-06-20 00:25:00
7 2 end 2019-06-20 00:30:00
8 2 start 2019-06-20 00:35:00
9 3 end 2019-06-20 00:40:00
10 3 start 2019-06-20 00:45:00
11 3 end 2019-06-20 00:50:00
12 3 start 2019-06-20 00:55:00
我的目标是将每个id的值映射到一个输出表中,其中只有一个start
和一个end
按连续的顺序(时间)。因此,输出将如下所示:
output
id start end
1 1 2019-06-20 00:00:00 2019-06-20 00:05:00
2 1 2019-06-20 00:10:00 2019-06-20 00:15:00
3 2 2019-06-20 00:25:00 2019-06-20 00:30:00
4 3 2019-06-20 00:45:00 2019-06-20 00:50:00
我尝试过使用dplyr
包,但是
test %>% group_by(id) %>% arrange(time) %>% starts_with("start")
Error in starts_with(., "start") : is_string(match) is not TRUE
starts_with
总是抛出一个错误。我希望避免编写for循环,因为我确信这可以通过几个链操作来处理。
发布于 2019-06-20 08:39:33
一种可能的方法是:
test[, {
si <- which(class=="start" & shift(class, -1L)=="end")
.(id, start=time[si], end=time[si + 1L])
}, by=.(id)]
输出:
id start end
1: 1 1 2019-06-20 00:00:00 2019-06-20 00:05:00
2: 1 1 2019-06-20 00:10:00 2019-06-20 00:15:00
3: 2 2 2019-06-20 00:25:00 2019-06-20 00:30:00
4: 3 3 2019-06-20 00:45:00 2019-06-20 00:50:00
数据:
library(data.table)
test <- fread("id,class,time
1,start,2019-06-20 00:00:00
1,end,2019-06-20 00:05:00
1,start,2019-06-20 00:10:00
1,end,2019-06-20 00:15:00
2,end,2019-06-20 00:20:00
2,start,2019-06-20 00:25:00
2,end,2019-06-20 00:30:00
2,start,2019-06-20 00:35:00
3,end,2019-06-20 00:40:00
3,start,2019-06-20 00:45:00
3,end,2019-06-20 00:50:00
3,start,2019-06-20 00:55:00")
发布于 2019-06-20 09:20:17
我通常使用cumsum()是这样的情况
test %>%
group_by(id) %>%
arrange(time, .by_group = TRUE) %>% # should use .by_group arg
mutate(flag = cumsum(class == "start")) %>%
group_by(id, flag) %>%
filter(n() == 2L) %>%
ungroup() %>%
spread(class, time) %>%
select(-flag)
发布于 2019-06-20 08:45:11
使用dplyr
和tidyr
,我们可以首先对遵循"start"
和"end"
模式的行进行filter
,创建两行一组,然后将其转换为长格式。
library(dplyr)
library(tidyr)
test %>%
group_by(id) %>%
filter(class == "start" & lead(class) == "end" |
class == "end" & lag(class) == "start") %>%
group_by(group = gl(n()/2, 2)) %>%
spread(class, time) %>%
ungroup() %>%
select(-group) %>%
select(id, start, end)
# id start end
# <int> <dttm> <dttm>
#1 1 2019-06-20 00:00:00 2019-06-20 00:05:00
#2 1 2019-06-20 00:10:00 2019-06-20 00:15:00
#3 2 2019-06-20 00:25:00 2019-06-20 00:30:00
#4 3 2019-06-20 00:45:00 2019-06-20 00:50:00
https://stackoverflow.com/questions/56677504
复制相似问题