【问题标题】:R data.table Perform Aggregate On Select Rows Using Full DatasetR data.table 使用完整数据集对选择行执行聚合
【发布时间】:2019-08-13 01:17:24
【问题描述】:

我正在使用 data.table 计算 R 中机器学习算法的特征。我只会对具有未来日期的行进行预测,但要计算每个特征,我需要聚合一个可以包含数百万行的大型数据集。但是,为了提高处理速度和性能,我不需要聚合来计算过去日期的行。

简单来说,我正在尝试使用大型数据集来计算仅使用整个数据集的最后 n 行的特征,并跳过日期过去的行。我有一个用户定义的函数,它计算高于循环中正在计算的当前行的行数。下面的示例 data.table 显示了我想要达到的结果。正在计算的行将计算比它高的行数,然后移动到循环中的下一行。我希望它跳过所有具有过去日期的行,只计算具有未来日期的行。本例中的当前日期为2019-03-20

Group         Date  Appt  Sum
    A   2019-03-18     1   NA
    A   2019-03-19     1   NA
    A   2019-03-20     1   NA
    A   2019-03-21     1    3
    A   2019-03-22     1    4
    A   2019-03-23     1    5

library(data.table)
dt = structure(list(Group = c("A", "A", "A", "A", "A", "A"), Date = structure(c(17973, 
17974, 17975, 17976, 17977, 17978), class = "Date"), Appt = c(1L, 
1L, 1L, 1L, 1L, 1L), Sum = c(NA, NA, NA, 3, 4, 5)), row.names = c(NA, 
-6L), class = "data.frame")
setDT(dt)

这是我目前正在使用的函数和代码,它运行良好。唯一的问题是它对每一行执行计算,即使我只需要数据集末尾几行的计算结果,可能是数百万。进行将从预测集中排除的计算会浪费大量的处理能力和时间。

rollingSum <- function(i, data, count, dates) {
  z <- with(data[i, ], zoo(count, dates))
  g <- zoo(, seq(start(z), end(z), by="day"))
  m <- merge(z, g)
  window(rollapplyr(m, 365, sum, na.rm=TRUE, partial=TRUE), time(z))
}

dt[, Sum := as.numeric(rollingSum(data=dt, count=Appt, dates=Date) - Appt), by=Group]

【问题讨论】:

  • 这只是dat[, sapply(Date, function(x) sum(x &gt; Date)), by=Group] 吗?
  • 如何将我的用户定义函数插入到这个解决方案中?
  • 你没有。我在想这会取代整个功能。
  • 我尝试了你的解决方案,但它仍然对每一行都计数。
  • 这可以替代您的用户功能吗? dt[, Sum2 := ifelse(Date &gt; as.IDate("2019-03-20"), (1:.N) - Appt , as.numeric(NA)), by = Group]

标签: r data.table aggregate


【解决方案1】:

这里是我上面评论的更多细节:

dt <- data.table(
  Group = "A",
  Date = as.IDate(c("2019-03-18", "2019-03-19", "2019-03-20",
                    "2019-03-21", "2019-03-22","2019-03-23")),
  Appt = 1)


microbenchmark(
  dt[, Sum := as.numeric(rollingSum(data=dt, count=Appt, dates=Date) - Appt), by=Group],
  dt[, Sum2 := ifelse(Date > as.IDate("2019-03-20"), (1:.N) - Appt , as.numeric(NA)), by = Group],unit = "ms")

以下是基准:

Unit: milliseconds
       expr      min        lq      mean   median       uq         max neval
 rollingSum 3.463955 4.0644910 18.748804 4.353562 4.745325 1395.840823   100
   new func 0.768079 0.8757095  1.258782 1.015766 1.140316    8.275985   100

【讨论】:

  • 谢谢雅各布。这个解决方案非常接近。它只计算未来的日期,但它不尊重自定义函数 rollingSum 中的 365 天范围限制。它只是计算同一组的所有记录。实际数据的输出可以追溯到 2 年前,但 rollingSum 函数只计算距当前计算行少于 365 天的行。在我的数据的实际输出中,Sum = 117 而 Sum2 = 371,因为 A 组总共有 372 行,但在 365 天范围内只有 117 行。
  • 我明白了... 想了一会儿,我只能想出这个:dt[Date &gt; today - (2 * this_window) - 1, Sum3 := rollapplyr(Appt, this_window, sum, na.rm = TRUE, partial = TRUE) - Appt, by=Group] 使用this_window &lt;- 365 你应该得到与 Sum2 中相同的结果,用于今天之后的行。之前的行有错误的结果,但那些你说你不需要的。此外,此解决方案还需要您将缺失的日期合并到其中 - 无论如何您都可以在 rollingSum 中执行此操作。我不知道这是否仍然更快,并且仍然在您不需要的行上完成计算。
  • 这里的主要思想是使用 rollapplr,而不是在 UDF 中,而是直接在 group by 中使用。
猜你喜欢
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
  • 2013-11-19
  • 2019-01-15
  • 2017-08-27
  • 1970-01-01
相关资源
最近更新 更多