每组填充时间序列的有效方法
Efficient way to Fill Time-Series per group
我一直在寻找一种方法来按时间、每组填充时间序列数据集。我使用的非常非常低效的方法是 split
每个组的数据集,并在该列表的所有元素中应用自定义时间序列填充函数(在最大值和最小值之间创建序列,然后合并)。不用说,这个操作不会通过拆分。
我的数据集看起来像,
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
...
我的尝试是利用 complete
函数来使用 tidyverse
方法,即
library(tidyverse)
d1 %>%
group_by(source) %>%
complete(source, grp = seq(min(grp), max(grp), by = 'hour'))
然而,大约 40-45 秒后,出现了一个进度条(显然是某些 tidyverse 函数中的一个巧妙功能 - 我怀疑 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")
看来 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
这也可以使用 zoo 来完成。这比问题中的代码和数据快一个数量级,但不如 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
我一直在寻找一种方法来按时间、每组填充时间序列数据集。我使用的非常非常低效的方法是 split
每个组的数据集,并在该列表的所有元素中应用自定义时间序列填充函数(在最大值和最小值之间创建序列,然后合并)。不用说,这个操作不会通过拆分。
我的数据集看起来像,
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 ...
我的尝试是利用 complete
函数来使用 tidyverse
方法,即
library(tidyverse)
d1 %>%
group_by(source) %>%
complete(source, grp = seq(min(grp), max(grp), by = 'hour'))
然而,大约 40-45 秒后,出现了一个进度条(显然是某些 tidyverse 函数中的一个巧妙功能 - 我怀疑 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")
看来 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
这也可以使用 zoo 来完成。这比问题中的代码和数据快一个数量级,但不如 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