R data.table 滑动窗口
Posted
技术标签:
【中文标题】R data.table 滑动窗口【英文标题】:R data.table sliding window 【发布时间】:2012-07-25 11:07:15 【问题描述】:使用 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))]
【问题讨论】:
+1。您能否提供有关数据大小和时间的更多信息。从您对艾伦回答的评论(艾伦和艾伦是不同的人?),它需要 6.4 秒(data.frame
需要 973 秒),您想进一步提高 6.4 秒吗?
艾伦和艾伦是不同的人:)。该数据集有约 650,000 行。我想出了一个工作速度更快但内存非常密集的解决方案。关于如何进一步改进它的任何想法?
【参考方案1】:
我在一个相关的帖子中解决了这个问题:https://***.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)
【讨论】:
【参考方案2】:此解决方案有效,但需要一段时间。
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)
【讨论】:
谢谢!不过,它似乎比 for 循环花费的时间更长。我从 system.time 获得的时间是 973s 用于您的代码 6.4s 用于循环。我想区别一定是data.table包的使用【参考方案3】:data.table
目前没有任何滚动窗口的特殊功能。在我对另一个类似问题的回答中进一步详细说明:
Is there a fast way to run a rolling regression inside data.table?
滚动中位数很有趣。它需要一个专门的功能才能有效地执行(与之前评论中的链接相同):
Rolling median algorithm in C
这里的问题和答案中的data.table
解决方案都非常低效,相对于适当的专用rollingmedian
函数(不适用于R afaik)。
【讨论】:
我们可以提高 FR#2185 的优先级吗? “为滑动窗口添加功能/文档”。从我的角度来看,它不需要是任何滚动总和、平均值等。最好有一种框架函数“rollfun =”或以下方法:我已经尝试过使用 roll=30、mult= 进行自我连接'all',allow.cartesian 实现它,没有成功。 “n”也可以很好地接受向量,而不仅仅是标量。 @MusX 好的,我已将优先级提高到顶部。【参考方案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)以使其正常工作。任何关于如何以较少内存密集型方式执行此操作的想法将不胜感激
【讨论】:
乍一看,for
中的rbind
将使用过多的 RAM。必须是一种更直接的方式来做到这一点。
This question 提到二分搜索,R 和 C 用于滚动中位数。看起来很有希望让您进一步调查;即,考虑算法。以上是关于R data.table 滑动窗口的主要内容,如果未能解决你的问题,请参考以下文章