输入范围的回归循环 - 如何避免 for 循环并提高性能?

Loop of regressions on input range - How can I avoid the for loop and improve performance?

我目前正在回测涉及 lm() 回归和概率 glm() 回归的策略。我有一个名为 forBacktest 的数据框,其中包含 200 行(每天回测 1 行)和 9 列:前 8 个(x1x8)是解释变量,最后一个( x9) 是实际值(我试图在回归中解释)。为了进行回归,我有另一个名为 temp 的数据框,它有大约 1000 行(每天一行)和很多列,其中一些是 x1x8 值还有 x9 值。

但棘手的部分是我不只是生成一个回归模型,然后为 predict 生成一个循环,因为 我 select 数据框的一部分 temp 基于 x1 的值,我将其分为 8 个不同的范围,然后根据数据框 forBacktest 的值 x1,我对 [=] 的一部分进行回归17=] 与 x1 在给定范围内。

所以我所做的是,对于 200 行中的每一行,我取 x1,如果 x1 介于 0 和 1 之间(例如),那么我创建 temp 其中所有 x1 都在 0 和 1 之间,然后我进行回归以用 x1x2、... x9 来解释 x9 (只有 x1+x2+...,没有 x1:x2x1^2,...)然后我将 predict 函数与数据框 forBacketst 一起使用。如果我预测一个正值并且 x9 为正,那么我将计数器 success 递增 1(如果两者均为负,同上),但如果一个为正,另一个为负,则 success 保持不变。然后我坐下一行,依此类推。在 200 行的末尾,我现在得到了成功的平均值 return。事实上,我有两个平均值:一个用于 lm 回归,另一个用于 glm 回归(相同的方法,我只是用 sign(x9) 作为变量来解释)。

所以我的问题是:我怎样才能在 R 中有效地做到这一点,如果可能的话,没有一个大的 for 循环和 200 次迭代,其中对于每次迭代,它创建数据框的一部分,进行回归,预测这两个值,将它们添加到计数器等等?(这是目前我的解决方案,但我发现它太慢而且不太像 R)

我的代码是这样的:

backtest<-function() {
    for (i in 1:dim(forBacktest)[1]) {
        x1 <- forBacktest[i,1]: x2 <- forBacktest[i,2] ... x9 <- forBacktest[i,9]
        a <- ifelse(x1>1.5,1.45,ifelse(x1>1,0.95,.... 
        b <- ifelse(x1>1.5,100,ifelse(x1>1,1.55,....
        temp2 <- temp[(temp$x1>=a/100)&(temp$x1<=b/100),]
        df <- dataframe(temp$x1,temp$x2,...temp$x9)
        reg <- lm(temp$x9~.,data=df)
        df2 <- data.frame(x1,x2,...x9)
        rReg <- predict(reg,df2)
        trueOrFalse <- ifelse(sign(rReg*x9)>0,1,0)
        success <- success+trueOrFalse
    }
    success
}            

你写的代码太复杂了。事情可以简单得多..

使用 cut()by() 函数。

breaks <- 0:8 #this is the range by which you want to divide your data
divider <- cut(forBackTest$x1,breaks)
subsetDat <- by(forBackTest,INDICES = divider,data.frame) # this creates 8 dataframes
reg <- lapply(subsetDat,lm,formula=x9~.) 

'reg' 现在将包含对应于 8 个范围的所有 8 个 lm 对象。要预测所有这些范围,请使用 lapply()reg 以及 temp 数据框。它将 return 为您提供八个范围的预测值

需要记住的几点:

  • 上面建议的方法更简单易读。这将是 比你的 for 循环更快,但随着数据框大小的增加, 它可能会变慢。
  • by 函数接受一个数据帧,并将指定的函数(data.frame()) 应用于由 INDICES 指定的子集数据帧和 returns 一个列表。因此创建了新的数据帧,这可能会占用一个很多 space 如果数据帧的大小很大。
  • *apply() 比 for 循环快得多。请参阅 here 了解更多信息。 apply 系列可以方便地进行此类操作