这类似于this dplyr lag post和this 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
这些步骤参考每行末尾的注释。
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库中确实没有解决方案,他会考虑这个问题。
答案 0 :(得分:6)
在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_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))