首先,让我们生成如下数据:
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循环吗?
答案 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)))