首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >R中按条件的值映射

R中按条件的值映射
EN

Stack Overflow用户
提问于 2019-06-20 08:27:15
回答 4查看 259关注 0票数 3

我有一个原始数据框,看起来像这样:

代码语言:javascript
复制
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按连续的顺序(时间)。因此,输出将如下所示:

代码语言:javascript
复制
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包,但是

代码语言:javascript
复制
test %>% group_by(id) %>% arrange(time) %>% starts_with("start")
Error in starts_with(., "start") : is_string(match) is not TRUE

starts_with总是抛出一个错误。我希望避免编写for循环,因为我确信这可以通过几个链操作来处理。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-06-20 08:39:33

一种可能的方法是:

代码语言:javascript
复制
test[, {
        si <- which(class=="start" & shift(class, -1L)=="end")
        .(id, start=time[si], end=time[si + 1L])
    }, by=.(id)]

输出:

代码语言:javascript
复制
   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

数据:

代码语言:javascript
复制
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")
票数 4
EN

Stack Overflow用户

发布于 2019-06-20 09:20:17

我通常使用cumsum()是这样的情况

代码语言:javascript
复制
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)
票数 3
EN

Stack Overflow用户

发布于 2019-06-20 08:45:11

使用dplyrtidyr,我们可以首先对遵循"start""end"模式的行进行filter,创建两行一组,然后将其转换为长格式。

代码语言:javascript
复制
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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56677504

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档