r语言 - 你能把dplyr::mutate和dplyr::lag默认=它自己的输入值吗?



这类似于这个dplyr滞后帖子,以及这个dplyr突变滞后帖子,但这两个帖子都没有问这个问题,默认为输入值。 我正在使用 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

"小时"是一个整数,但应该是一个时间戳。

"快照">

是 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( 将两个整数"日期"字段连接成一个字段,
  • c( 将合并的整数"日期"字段转换为 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

如果我使用 fulldate1,它确实有效,但随后我丢失了group_by(ip)结果,这是必要的。 是否可以在 dplyr 中使滞后引用成为自己的输入?

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

在 OP 的代码中...

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

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

相关案例:

  • 同样,有了"领先",我们想要dplyr::lead(x, default=last(x)).
  • 如果滞后或领先超过一步(n大于 1(,default=无法做到这一点,我们可能需要切换到if_elsecase_when或类似。(我不确定当前的整洁成语。

我认为弗兰克的解决方案效果很好。以下是完整的示例:


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

怎么样

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

最新更新