我有这个数据框,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.
有没有办法强加这种逻辑?
谢谢.
两种选择:
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)与ifelseifelse不方便地剥离属性,因此您必须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)