49

使用 data.table 包实现滑动窗口功能的最佳(最快)方法是什么?

我正在尝试计算滚动中位数,但每个日期有多个行(由于 2 个附加因素),我认为这意味着 zoo rollapply 函数不起作用。这是一个使用简单 for 循环的示例:

library(data.table)
df <- data.frame(
  id=30000,
  date=rep(as.IDate(as.IDate("2012-01-01")+0:29, origin="1970-01-01"), each=1000),
  factor1=rep(1:5, each=200),
  factor2=1:5,
  value=rnorm(30, 100, 10)
)

dt = data.table(df)
setkeyv(dt, c("date", "factor1", "factor2"))

get_window <- function(date, factor1, factor2) {
  criteria <- data.table(
    date=as.IDate((date - 7):(date - 1), origin="1970-01-01"),
    factor1=as.integer(factor1),
    factor2=as.integer(factor2)
  )
  return(dt[criteria][, value])
}

output <- data.table(unique(dt[, list(date, factor1, factor2)]))[, window_median:=as.numeric(NA)]

for(i in nrow(output):1) {
  print(i)
  output[i, window_median:=median(get_window(date, factor1, factor2))]
}
4

4 回答 4

9

data.table目前没有任何滚动窗口的特殊功能。我在此处对另一个类似问题的回答中提供了更多详细信息:

有没有一种快速的方法可以在 data.table 中运行滚动回归?

滚动中位数很有趣。它需要一个专门的功能才能有效地执行(与前面评论中的链接相同):

C中的滚动中值算法

相对于适当的专用功能(R afaik 不可用) ,此处问题和答案中的data.table解决方案都非常低效。rollingmedian

于 2012-08-31T11:26:52.533 回答
4

通过创建滞后数据集并进行大量连接,我设法将示例缩短到 1.4 秒。

df <- data.frame(
  id=30000,
  date=rep(as.IDate(as.IDate("2012-01-01")+0:29, origin="1970-01-01"), each=1000),
  factor1=rep(1:5, each=200),
  factor2=1:5,
  value=rnorm(30, 100, 10)
)

dt2 <- data.table(df)
setkeyv(dt, c("date", "factor1", "factor2"))

unique_set <-  data.table(unique(dt[, list(original_date=date, factor1, factor2)]))
output2 <- data.table()
for(i in 1:7) {
  output2 <- rbind(output2, unique_set[, date:=original_date-i])
}    

setkeyv(output2, c("date", "factor1", "factor2"))
output2 <- output2[dt]
output2 <- output2[, median(value), by=c("original_date", "factor1", "factor2")]

这在这个测试数据集上运行良好,但在我的真实数据集上它失败了,只有 8GB 的​​ RAM。我将尝试升级到一个 High Memory EC2 实例(具有 17、34 或 68GB RAM)以使其正常工作。任何关于如何以较少内存密集型方式执行此操作的想法将不胜感激

于 2012-08-10T15:00:36.620 回答
0

此解决方案有效,但需要一段时间。

df <- data.frame(
  id=30000,
  date=rep(seq.Date(from=as.Date("2012-01-01"),to=as.Date("2012-01-30"),by="d"),each=1000),
  factor1=rep(1:5, each=200),
  factor2=1:5,
  value=rnorm(30, 100, 10)
)

myFun <- function(dff,df){
    median(df$value[df$date>as.Date(dff[2])-8 & df$date<as.Date(dff[2])-1 & df$factor1==dff[3] & df$factor2==dff[4]])
}

week_Med <- apply(df,1,myFun,df=df)

week_Med_df <- cbind(df,week_Med)
于 2012-07-27T15:28:16.400 回答
0

我在相关线程中解决了这个问题:https ://stackoverflow.com/a/62399700/7115566

我建议研究一下这个frollapply功能。例如,见下文

library(data.table)
set.seed(17)
dt <- data.table(i = 1:100,
             x = sample(1:10, 100, replace = T),
             y = sample(1:10, 100, replace = T))
dt$index <- dt$x == dt$y
dt[,`:=` (MA = frollapply(index,10,mean)), ]
head(dt,12)
于 2020-06-16T23:55:55.707 回答