每组填充时间序列的有效方法

时间:2017-10-12 14:37:16

标签: r data.table tidyverse

我正在寻找一种方法来按时间,每组填写时间序列数据集。我使用的效率非常低效的方法是split每组数据集,并在该列表的所有元素中应用自定义时间序列填充函数(在max和min之间创建序列,并合并)。毋庸置疑,这项行动不会通过分裂。

我的数据集看起来像,

    source                 grp cnt
 1:     83 2017-06-06 13:00:00   1
 2:     83 2017-06-06 23:00:00   1
 3:     83 2017-06-07 03:00:00   1
 4:     83 2017-06-07 07:00:00   2
 5:     83 2017-06-07 13:00:00   1
 6:     83 2017-06-07 19:00:00   1
 7:     83 2017-06-08 00:00:00   1
 8:     83 2017-06-08 14:00:00   1
 9:     83 2017-06-08 15:00:00   1
10:     83 2017-06-08 20:00:00   1
11:    137 2017-06-04 02:00:00   1
12:    137 2017-06-04 05:00:00   1
13:    137 2017-06-04 23:00:00   1
...

我的尝试是利用tidyverse函数来使用complete方法,即

library(tidyverse)

d1 %>% 
 group_by(source) %>% 
 complete(source, grp = seq(min(grp), max(grp), by = 'hour'))

然而,在大约40-45秒之后,出现了一个进度条(显然在一些整齐的功能中有一个很好的特征 - 我怀疑在这种情况下complete)估计完成了9个小时。我的数据集非常大,这不是最轻的操作,所以我正在寻找真正有效的东西。

数据

#dput(d1)
structure(list(source = c("83", "83", "83", "83", "83", "83", 
"83", "83", "83", "83", "137", "137", "137", "137", "137", "137", 
"137", "137", "137", "137", "137", "137", "137", "137"), grp = structure(c(1496743200, 
1496779200, 1496793600, 1496808000, 1496829600, 1496851200, 1496869200, 
1496919600, 1496923200, 1496941200, 1496530800, 1496541600, 1496606400, 
1496617200, 1496649600, 1496696400, 1496808000, 1496844000, 1496876400, 
1496962800, 1497880800, 1497888000, 1497978000, 1497996000), class = c("POSIXct", 
"POSIXt"), tzone = ""), cnt = c(1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L
)), .Names = c("source", "grp", "cnt"), row.names = c(NA, -24L
), class = "data.frame")

2 个答案:

答案 0 :(得分:4)

data.table似乎比tidyverse选项快得多。因此,只需将上述内容翻译成data.table(@Frank的称赞),就可以在不到3分钟的时间内完成操作。

library(data.table)

mDT = setDT(d1)[, .(grp = seq(min(grp), max(grp), by = "hour")), by = source]
new_D <- d1[mDT, on = names(mDT)]

new_D <- new_D[, cnt := replace(cnt, is.na(cnt), 0)] #If needed

答案 1 :(得分:1)

这也可以使用动物园来完成。这比问题中的代码和数据快一个数量级,但没有data.table解决方案那么快,尽管如果不需要下面显示的最后一行代码,有可能进一步加速它。

我们将d1读入动物园对象z,将其拆分为一个多变量时间序列,每个时间序列都有一个列。然后,我们将其与具有所有时间的零宽度系列合并,并使用melt=TRUE参数将其强化回数据框,以获得长格式data.frame。如果可以使用宽形式的多变量动物园系列,那么你可以跳过最后一行,在这种情况下它会更快。

library(zoo)

z <- read.zoo(d1, split = 1, index = 2) # wide form
zz <- merge(z, zoo(, seq(start(z), end(z), "hour"))) # expand
fortify(zz, melt = TRUE) # convert to long form data.frame