你能使dplyr :: mutate和dplyr :: lag默认=它自己的输入值吗?

时间:2017-08-18 20:23:29

标签: r dplyr lag mutate

这类似于this dplyr lag postthis dplyr mutate lag post,但这些都没有提出有关默认输入值的问题。我正在使用dplyr来改变一个新字段,该字段是另一个字段的滞后偏移量(我已转换为POSIXct)。目标是,对于给定的ip,我想知道一些关于它在我的列表中显示的所有时间之间的增量的汇总统计数据。我也有大约1200万行。

数据看起来像这样(突变之前)

ip             hour         snap
192.168.1.2    2017070700    0
192.168.1.2    2017070700   15
192.168.1.4    2017070700    0
192.168.1.4    2017070701   45
192.168.1.4    2017070702   30
192.168.1.7    2017070700   15

'hour'是一个整数,但应该是一个时间戳。

'snap'是4个'快照'值之一,代表15分钟的增量。

这是data.frame创建代码:

test <- data.frame(ip=c("192.168.1.2","192.168.1.2","192.168.1.4","192.168.1.4","192.168.1.4","192.168.1.7"), hour=c(2017070700,2017070700,2017070700,2017070701,2017070702,2017070700), snap=c(0,15,0,45,30,15))

每个ip有数百甚至数千个时间戳。下面的代码使用dplyr

  • a)用前导0填充0,
  • b)将两个整数'date'字段连接成一个字段
  • c)将合并的整数'date'字段转换为POSIX日期
  • d)通过ip分组,
  • e)将一个滞后于旧时间戳的新列变为1,如果该值为NA,则返回原始值(这就是“没有工作的位置”)和
  • f)改变一个新列,它取当前时间和前一个时间的差异(通过ip)。

这些步骤参考每行末尾的注释。

timedelta <- test %>% 
  mutate(snap = formatC(snap, width=2, flag=0)) %>%                      # a) 
  mutate(fulldateint = paste(hour, snap, sep="")) %>%                    # b) 
  mutate(fulldate = as.POSIXct(strptime(fulldateint, "%Y%m%d%H%M"))) %>% # c) 
  group_by(ip) %>%                                                       # d) 
  mutate(shifted = dplyr::lag(fulldate, default=fulldate)) %>%           # e) 
  mutate(diff = fulldate-shifted)                                        # f) 

突变后,数据应如下所示:

           ip       hour  snap  fulldateint            fulldate             shifted      diff
       <fctr>      <dbl> <chr>        <chr>              <dttm>              <dttm>    <time>
1 192.168.1.2 2017070700    00 201707070000 2017-07-07 00:00:00 2017-07-07 00:00:00    0 secs
2 192.168.1.2 2017070700    15 201707070015 2017-07-07 00:15:00 2017-07-07 00:00:00  900 secs
3 192.168.1.4 2017070700    00 201707070000 2017-07-07 00:00:00 2017-07-07 00:00:00    0 secs
4 192.168.1.4 2017070701    45 201707070145 2017-07-07 01:45:00 2017-07-07 00:00:00 6300 secs
5 192.168.1.4 2017070702    30 201707070230 2017-07-07 02:30:00 2017-07-07 01:45:00 2700 secs
6 192.168.1.7 2017070700    15 201707070015 2017-07-07 00:15:00 2017-07-07 00:15:00    0 secs

如果我可以使滞后默认为其原始值,那么当'delta-T'没有先前的值(这是期望的结果)时,它将始终为0。

但是,dplyr::lag(fulldate, default=fulldate)会抛出错误

Error in mutate_impl(.data, dots) : 
Column `shifted` must be length 2 (the group size) or one, not 3

如果我使用fulldate 1,它确实有效,但是我失去了group_by(ip)结果,这是必要的。是否有可能在dplyr中使滞后引用自己的输入?

注意:我真的更喜欢使用dplyr而不是data.table的答案,如果可能的话,因为我一直使用dplyr作为我们的主要数据调整库,但是因为我想向Wickham先生建议如果在现有的dplyr库中确实没有解决方案,他会考虑这个问题。

3 个答案:

答案 0 :(得分:6)

在OP的代码中......

...
d) group_by(ip) %>%
e) mutate(shifted = dplyr::lag(fulldate, default=fulldate)) %>%
...

default=参数的长度应为1。用default = first(fulldate)替换OP的代码应该适用于这种情况(因为第一个元素不会有滞后,所以我们需要应用默认值)。

相关案例:

  • 同样,使用&#34;引导&#34;,我们需要dplyr::lead(x, default=last(x))
  • 如果滞后或超过一步(n大于1),default=无法执行此操作,我们可能需要切换到if_else或{ {1}}或类似的。 (我不确定当前的tidyverse习语。)

答案 1 :(得分:3)

我认为Frank的解决方案非常有效。这是完整的例子:


library(dplyr, warn.conflicts = F)

test <- data.frame(ip=c("192.168.1.2","192.168.1.2","192.168.1.4","192.168.1.4","192.168.1.4","192.168.1.7"),
                   hour=c(2017070700,2017070700,2017070700,2017070701,2017070702,2017070700),
                   snap=c(0,15,0,45,30,15))


test %>%
  mutate(snap = formatC(snap, width = 2, flag = 0)) %>%
  mutate(fulldateint = paste(hour, snap, sep = "")) %>%
  mutate(fulldate = as.POSIXct(strptime(fulldateint, "%Y%m%d%H%M"))) %>%
  group_by(ip) %>%
  mutate(shifted = lag(fulldate, default = first(fulldate))) %>%
  mutate(diff = fulldate - shifted) %>% 
  ungroup() %>% 
  select(ip, fulldate, shifted, diff)

#> # A tibble: 6 x 4
#>            ip            fulldate             shifted      diff
#>        <fctr>              <dttm>              <dttm>    <time>
#> 1 192.168.1.2 2017-07-07 00:00:00 2017-07-07 00:00:00    0 secs
#> 2 192.168.1.2 2017-07-07 00:15:00 2017-07-07 00:00:00  900 secs
#> 3 192.168.1.4 2017-07-07 00:00:00 2017-07-07 00:00:00    0 secs
#> 4 192.168.1.4 2017-07-07 01:45:00 2017-07-07 00:00:00 6300 secs
#> 5 192.168.1.4 2017-07-07 02:30:00 2017-07-07 01:45:00 2700 secs
#> 6 192.168.1.7 2017-07-07 00:15:00 2017-07-07 00:15:00    0 secs

答案 2 :(得分:0)

怎么样

ifelse(is.na(lag(value)), value, lag(value))