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

时间:2012-08-27 10:06:06

标签: r data.table zoo

我在R中运行滚动回归,使用存储在data.table中的数据。

我有一个正常工作的版本,但它感觉就像一个黑客 - 我真的使用我在zoo包中知道的内容,而data.table中没有任何魔法因此,感觉比它应该的慢。

结合约书亚的建议 - 下面 - 使用lm.fit而非lm加速约为12倍。

(修订版)示例代码:

require(zoo)
require(data.table)
require(rbenchmark)
set.seed(1)

tt <- seq(as.Date("2011-01-01"), as.Date("2012-01-01"), by="day")
px <- rnorm(366, 95, 1)

DT <- data.table(period=tt, pvec=px)

dtt <- DT[,tnum:=as.numeric(period)][, list(pvec, tnum)]
dtx <- as.matrix(DT[,tnum:=as.numeric(period)][, tnum2:= tnum^2][, int:=1][, list(pvec, int, tnum, tnum2)])

rollreg <- function(dd) coef(lm(pvec ~ tnum + I(tnum^2), data=as.data.frame(dd)))
rollreg.fit <- function(dd) coef(lm.fit(y=dd[,1], x=dd[,-1]))

rr <- function(dd) rollapplyr(dd, width=20, FUN = rollreg, by.column=FALSE)
rr.fit <- function(dd) rollapplyr(dd, width=20, FUN = rollreg.fit, by.column=FALSE)

bmk <- benchmark(rr(dtt), rr.fit(dtx), 
         columns = c('test', 'elapsed', 'relative'),
         replications = 10,
         order = 'elapsed'
       )

     test elapsed relative
2 rr.fit(dtx)    0.48   1.0000
1     rr(dtt)    5.85  12.1875

尝试应用所显示的知识herehere,我制作了以下简单滚动回归函数我认为使用了一些data.table操作的速度。

请注意,问题稍微不同(并且更加真实):采用向量,添加滞后,并对自身进行回归。这类AR型问题相当广泛。

我在这里分享,因为它可能有用,我肯定它可以改进(我会随着我的改进而更新):

require(data.table)
set.seed(1)
x  <- rnorm(1000)
DT <- data.table(x)
DTin <- data.table(x)

lagDT <- function(DTin, varname, l=5)
{
    i = 0
    while ( i < l){
        expr <- parse(text = 
                  paste0(varname, '_L', (i+1), 
                     ':= c(rep(NA, (1+i)),', varname, '[-((length(',     varname, ') - i):length(', varname, '))])'
                 )
              )
    DTin[, eval(expr)]
    i <- i + 1
}
return(DTin)
}   

rollRegDT <- function(DTin, varname, k=20, l=5)
{
adj <- k + l - 1
.x <- 1:(nrow(DTin)-adj)
DTin[, int:=1]
dtReg <- function(dd) coef(lm.fit(y=dd[-c(1:l),1], x=dd[-c(1:l),-1]))
eleNum <- nrow(DTin)*(l+1)
outMatx <- matrix(rep(NA, eleNum), ncol = (l+1))
colnames(outMatx) <- c('intercept', 'L1', 'L2', 'L3', 'L4', 'L5')
for (i in .x){
    dt_m <- as.matrix(lagDT(DTin[i:(i+adj), ], varname, l))
    outMatx[(i+(adj)),] <- dtReg(dt_m)
}
return(outMatx)
}

rollCoef <- rollRegDT(DT, varname='x')

2 个答案:

答案 0 :(得分:5)

据我所知; data.table没有滚动窗口的任何特殊功能。其他包已经在向量上实现滚动功能,因此可以在j data.table中使用它们。如果它们没有足够的效率,并且没有包有更快的版本(?),那么它自己编写更快的版本并且(当然)贡献它们:要么是现有的包,要么创建自己的包。

相关问题(请点击链接中的链接):

Using data.table to speed up rollapply
R data.table sliding window
Rolling regression over multiple columns in R

答案 1 :(得分:0)

使用roll_regres包中的rollRegres功能,你可以快14585 / 766~19倍

require(zoo)
require(data.table)
require(microbenchmark)
set.seed(1)

tt <- seq(as.Date("2011-01-01"), as.Date("2012-01-01"), by="day")
px <- rnorm(366, 95, 1)

DT <- data.table(period=tt, pvec=px)

dtt <- DT[,tnum:=as.numeric(period)][, list(pvec, tnum)]

# this is a quite bad problem as tnum and the square has a high cor
cor(dtt$tnum, dtt$tnum^2)
#R [1] 0.9999951

# so we center it to avoid numerical issues in the comparisons
dtt$tnum <- dtt$tnum - mean(dtt$tnum)
cor(dtt$tnum, dtt$tnum^2)
#R [1] -2.355659e-21

dtx <- as.matrix(DT[,tnum:=as.numeric(period)][, tnum2:= tnum^2][, int:=1][, list(pvec, int, tnum, tnum2)])

rollreg <- function(dd)
  coef(lm(pvec ~ tnum + I(tnum^2), data = as.data.frame(dd)))
rollreg.fit <- function(dd) coef(lm.fit(y=dd[,1], x=dd[,-1]))

rr <- function(dd) rollapplyr(
  dd, width=20, FUN = rollreg, by.column = FALSE, align = "right")
rr.fit <- function(dd) rollapplyr(
  dd, width=20, FUN = rollreg.fit, by.column = FALSE, align = "right")

#####
# use rollRegres
library(rollRegres)
rollreg_out    <- rr(dtt)
rollRegres_out <- roll_regres(pvec ~ tnum + I(tnum^2), dtt, width = 20L)

# show that they give the same
all.equal(rollRegres_out$coefs[-(1:19), ], rollreg_out,
          check.attributes = FALSE)
#R [1] "Mean relative difference: 4.985435e-08"

#####
# benchmark
microbenchmark(
  rr = rr(dtt),
  rr.fit = rr.fit(dtx),
  roll_regres = roll_regres(pvec ~ tnum + I(tnum^2), dtt ,width = 20L),
  times = 5)
#R Unit: microseconds
#R expr        min         lq        mean     median         uq       max neval
#R          rr 279404.357 279456.901 282071.3414 279989.840 282201.396 289304.21     5
#R      rr.fit  13744.598  14017.981  14585.2106  14147.166  14887.117  16129.19     5
#R roll_regres    621.037    660.939    766.7364    721.383    843.853    986.47     5