使用dplyr铅但有一些约束

时间:2016-09-26 23:50:08

标签: r dplyr

我有这个数据框,dat和dplyr用于添加“NextStatTime”字段,该字段是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

这非常接近正确的答案,但如果缺少身份证,它仍会计算并产生误导。

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

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

谢谢。

2 个答案:

答案 0 :(得分:2)

我想使用POSIXct留下替代方法。您可以通过以下方式避免数字到日期转换。如果在dplyr包中使用if_else(),它会关心类。你想要做的是将POSIXct类保留在函数中。如果您输入typeof(dat$StartTime),您会发现StartTime是双倍的。它的类是POSIXct。因此,您希望使用NA_real_并将NA视为POSIXct。请确保您提供原产地和时区。在我的情况下,我需要按顺序将我的时区指定为“亚洲/东京”或产生预期结果。

library(dplyr)
group_by(dat, ID) %>%
mutate(NextStartTime = if_else(abs(NumberInSequence - lead(NumberInSequence)) != 1,
                               true = as.POSIXct(NA_real_, origin = "1970-01-01 00:00:00", tz = "Asia/Tokyo"),
                               false = lead(StartTime)),
       Duration = difftime(NextStartTime, EndTime, unit = "s"))


#     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

答案 1 :(得分:1)

两个选项:

<script type="text/javascript"> function Link() { document.getElementById("TestMe").src = "http://www.cnn.com"; } </script> <table> <td bgcolor="#a7d331" height="10" align="center" style="cursor:pointer" onclick="window.open('http://www.yahoo.com'); Link();"><font face="Arial" color="FFFFFF" size="4" alt="English">Some Link</font></td> </table> <iframe id="TestMe" src="" frameborder="0" scrolling="no" width="400px" height="400px"></iframe>

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

下行:您新添加了tidyr::complete行。不过,你可以在事后小心NA来省略它们 Upside :它易于编写和理解,并保留原始逻辑。

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

子集lead(StartTime)

ifelse不方便剥离属性,因此如果不将结果整数重新转换回POSIXct,则无法执行ifelse,这很麻烦。相反,使用ifelse(lead(StartTime) == NumberInSequence + 1, lead(StartTime), NA)进行子集更容易,如果它不匹配则传递ifelse,因此索引向量将返回NA而不是任何内容。

下行:为了保持类型,写作很糟糕 上行:不会添加其他行。

NA