R中条件的值映射

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

我有一个原始数据框,如下所示:

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

我的目标是在存在a startend连续顺序(时间)的情况下将值映射到每个id的输出表。因此,输出看起来像:

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循环,因为我确信这可以通过一些链操作来处理。有关解决方法的任何想法dplyrdata.table

提问于
用户回答回答于

一种可能的方法:

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")
用户回答回答于

你可以保留每一start行加上end它后面的那一行(如果有的话),然后dcast用来从长形式切换到宽形式:

test[, 
  if (.N >= 2) head(.SD, 2)
, by=.(g = rleid(id, cumsum(class=="start"))), .SDcols=names(test)][, 
  dcast(.SD, id + g ~ factor(class, levels=c("start", "end")), value.var="time")
]

   id g               start                 end
1:  1 1 2019-06-20 00:00:00 2019-06-20 00:05:00
2:  1 2 2019-06-20 00:10:00 2019-06-20 00:15:00
3:  2 4 2019-06-20 00:25:00 2019-06-20 00:30:00
4:  3 7 2019-06-20 00:45:00 2019-06-20 00:50:00

rleidcumsum用于查找序列; 并且factor需要告诉dcast列顺序。

旁注:这与@ cheetahfly的答案基本相同(我发布的时候没有意识到):因为cumsum正在增加,所以按id + cumsum分组就足够了,并且不需要使用rleid(用于跟踪)价值观)。唯一的区别是我的方法可以保持一个像开始,结束,结束的运行; 而另一个答案将使用n()== 2检查过滤掉它。

扫码关注云+社区

领取腾讯云代金券