R slide.table скользящее окно
Каков наилучший (самый быстрый) способ реализовать скользящую функцию окна с пакетом data.table?
Я пытаюсь вычислить скользящую медиану, но имеет несколько строк в день (из-за двух дополнительных факторов), что, я думаю, означает, что функция zap rollapply не будет работать. Вот пример использования наивного цикла:
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
data.table
в настоящее время не имеет специальных функций для перекатывания окон. Более подробно здесь, в моем ответе на другой аналогичный вопрос:
Есть ли быстрый способ запустить скользящую регрессию внутри data.table?
Роллинг медиана интересна. Для эффективной работы потребуется специальная функция (та же ссылка, что и в предыдущем комментарии):
Передвижной медианный алгоритм в C
Решения data.table
в вопросе и ответах здесь очень неэффективны относительно соответствующей специализированной функции rollingmedian
(которая недоступна для R afaik).
Ответ 2
Мне удалось получить пример до 1.4s, создав запаздывающий набор данных и сделав огромное объединение.
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")]
Это очень хорошо работает в этом тестовом наборе данных, но на самом деле он не работает с 8 ГБ оперативной памяти. Я попытаюсь перейти к одному из экземпляров High Memory EC2 (с 17, 34 или 68 ГБ оперативной памяти), чтобы заставить его работать. Любые идеи о том, как сделать это с меньшим объемом памяти, будут оценены
Ответ 3
Это решение работает, но требуется некоторое время.
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)