如何在自变量中未向量化的自定义函数中使用lapply函数代替for循环

时间:2019-05-02 16:04:52

标签: r data.table

首先,让我们生成如下数据:

library(data.table)
data <- data.table(date = as.Date("2015-05-01")+0:299)
set.seed(123)
data[,":="(
   a = round(30*cumprod(1+rnorm(300,0.001,0.05)),2),
   b = rbinom(300,5000,0.8)
 )]

然后我想使用我的自定义函数多次操作多个列,而无需手动输入。例如,我的自定义函数为add <- function(x,n) (x+n)

我提供如下的for循环代码:

add <- function(x,n) (x+n)
n <- 3
freture_old <- c("a","b")
for(i in 1:n ){
  data[,(paste0(freture_old,"_",i)) := add(.SD,i),.SDcols =freture_old ]
}

您能告诉我一个lapply版本而不是for循环吗?

2 个答案:

答案 0 :(得分:5)

如果只想使用lapply循环而不是for循环,则您实际上不需要进行太多更改。对于data.table对象,它变得更加容易,因为每次迭代都会更改data.table,而不必将副本保存到全局环境中。我添加的只是抑制控制台输出的一件事是在其周围包裹一个invisible

lapply(1:n,function(i) data[,paste0(freture_old,"_",i):=lapply(.SD,add,i),.SDcols =freture_old])

请注意,如果将此lapply分配给对象,则会得到data.tables的列表,该列表的大小为迭代次数或在这种情况下为3。这将浪费内存,因为您实际上只对最终对象感兴趣条目。因此,只需运行代码而不将其分配给变量即可。现在,如果您不将其分配给任何内容,则将把每次迭代输出到控制台。因此,我建议像这样将invisible包裹起来:

invisible(lapply(1:n,function(i) data[,paste0(freture_old,"_",i):=lapply(.SD,add,i),.SDcols =freture_old]))

希望这会有所帮助,让我知道是否需要我在此答案中添加其他内容。祝你好运!

答案 1 :(得分:1)

不带R“循环”的选项(因为最终在某处某个级别的循环而被引用):

data[,
    c(outer(freture_old, seq_len(n), paste, sep="_")) :=
        as.data.table(matrix(outer(as.matrix(.SD), seq_len(n), add), .N)),
    .SDcols=freture_old]

或等效地在基数R中:

setDF(data)
cbind(data, matrix(outer(as.matrix(data[, freture_old]), seq_len(n), add), 
    nrow(data)))