使用dplyr铅但有一些约束

use*_*875 5 r dplyr

我有这个数据框,dat和dplyr用于添加"NextStatTime"字段,该字段是ID结束时间之后的开始时间,"持续时间"是从结束时间到下一个开始时间的时间. ID.

数据如下所示:

     dat = data.frame(ID= c(1,1,1,2,3,3),
                      NumberInSequence= c(1,3,4,1,1,2),
                      StartTime = as.POSIXct(c("2016-01-01 05:52:05 GMT","2016-01-01 05:52:11 GMT","2016-01-01 05:52:16 GMT","2016-01-01 05:40:05 GMT","2016-01-01 06:12:13 GMT","2016-01-01 07:12:26 GMT"))  ,
                      EndTime = as.POSIXct(c("2016-01-01 05:52:10 GMT","2016-01-01 05:52:16 GMT","2016-01-01 05:52:30 GMT","2016-01-01 05:46:05 GMT","2016-01-01 06:12:25 GMT","2016-01-01 08:00:00 GMT")  )
                       )

    dat
    dat %>% group_by(ID) %>% mutate(NextStartTime = lead(StartTime), duration = as.numeric(difftime(NextStartTime, EndTime, units = 's')))

  ID NumberInSequence           StartTime             EndTime       NextStartTime duration
  <dbl>            <dbl>              <time>              <time>              <time>    <dbl>
1     1                1 2016-01-01 05:52:05 2016-01-01 05:52:10 2016-01-01 05:52:11        1
2     1                3 2016-01-01 05:52:11 2016-01-01 05:52:16 2016-01-01 05:52:16        0
3     1                4 2016-01-01 05:52:16 2016-01-01 05:52:30                <NA>       NA
4     2                1 2016-01-01 05:40:05 2016-01-01 05:46:05                <NA>       NA
5     3                1 2016-01-01 06:12:13 2016-01-01 06:12:25 2016-01-01 07:12:26     3601
6     3                2 2016-01-01 07:12:26 2016-01-01 08:00:00                <NA>       NA
Run Code Online (Sandbox Code Playgroud)

这非常接近正确答案,但如果缺少ID,它仍会计算并产生误导.

例如 - 看ID = 1,有3个条目,序列号为1,3和4.序列中没有#2.它缺失所以ID = 1的NextStartTime和持续时间以及序列中的数字= 1应该是NA NOT 05:52:11和1.

有没有办法强加这种逻辑?

谢谢.

ali*_*ire 1

两种选择:


tidyr::complete

一种选择是使用tidyr::complete填充缺失的行,并使用前面的方法。

缺点:您会NA添加新的大部分行。不过,您可以在事后仔细调用来忽略它们filter
优点:易于编写和理解,并且保留了原始逻辑。

library(tidyverse)

dat %>% group_by(ID) %>% 
    complete(NumberInSequence = seq(max(NumberInSequence))) %>% 
    mutate(NextStartTime = lead(StartTime), 
           Duration = as.numeric(difftime(NextStartTime, EndTime, units = 's')))

## Source: local data frame [7 x 6]
## Groups: ID [3]
## 
##      ID NumberInSequence           StartTime             EndTime       NextStartTime Duration
##   <dbl>            <dbl>              <dttm>              <dttm>              <dttm>    <dbl>
## 1     1                1 2016-01-01 05:52:05 2016-01-01 05:52:10                <NA>       NA
## 2     1                2                <NA>                <NA> 2016-01-01 05:52:11       NA
## 3     1                3 2016-01-01 05:52:11 2016-01-01 05:52:16 2016-01-01 05:52:16        0
## 4     1                4 2016-01-01 05:52:16 2016-01-01 05:52:30                <NA>       NA
## 5     2                1 2016-01-01 05:40:05 2016-01-01 05:46:05                <NA>       NA
## 6     3                1 2016-01-01 06:12:13 2016-01-01 06:12:25 2016-01-01 07:12:26     3601
## 7     3                2 2016-01-01 07:12:26 2016-01-01 08:00:00                <NA>       NA
Run Code Online (Sandbox Code Playgroud)

子集lead(StartTime)ifelse

ifelse不方便地剥离属性,因此您必须ifelse(lead(StartTime) == NumberInSequence + 1, lead(StartTime), NA)将结果整数重新转换回 POSIXct,这很麻烦。相反,使用 进行子集化更容易,如果不匹配ifelse则传递 an ,因此索引的向量会返回而不是什么也不返回。NANA

缺点:为了保持类型而编写很挑剔。
优点:不添加额外的行。

dat %>% group_by(ID) %>% 
    mutate(NextStartTime = lead(StartTime)[ifelse(lead(NumberInSequence) == (NumberInSequence + 1), TRUE, NA)], 
           duration = difftime(NextStartTime, EndTime, units = 's'))

## Source: local data frame [6 x 6]
## Groups: ID [3]
## 
##      ID NumberInSequence           StartTime             EndTime       NextStartTime  duration
##   <dbl>            <dbl>              <dttm>              <dttm>              <dttm>    <time>
## 1     1                1 2016-01-01 05:52:05 2016-01-01 05:52:10                <NA>   NA secs
## 2     1                3 2016-01-01 05:52:11 2016-01-01 05:52:16 2016-01-01 05:52:16    0 secs
## 3     1                4 2016-01-01 05:52:16 2016-01-01 05:52:30                <NA>   NA secs
## 4     2                1 2016-01-01 05:40:05 2016-01-01 05:46:05                <NA>   NA secs
## 5     3                1 2016-01-01 06:12:13 2016-01-01 06:12:25 2016-01-01 07:12:26 3601 secs
## 6     3                2 2016-01-01 07:12:26 2016-01-01 08:00:00                <NA>   NA secs
Run Code Online (Sandbox Code Playgroud)