【问题标题】:How to use lapply function to instead of for loop in a custom function which is not vectorized in arguments如何在未在参数中矢量化的自定义函数中使用 lapply 函数而不是 for 循环
【发布时间】:2019-05-02 16:04:52
【问题描述】:

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

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 &lt;- 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 循环吗?

【问题讨论】:

  • for 循环有什么问题?注意:lapply 也是一个循环。
  • 在 R 中,lapply 循环似乎比 for 循环运行得更快。
  • 我同意 Parfait 在此处重新使用 for 循环,尽管您应该使用 lapply 来迭代 .SD,例如 for (i in 1:n) data[, paste0(freture_old,"_",i) := lapply(.SD, add, i), .SDcols=freture_old][]
  • @Frank - 是 +1 用于迭代 data.table 中的 .SD,我将修改我的答案以包括它,因为这确实是使用 data.table 的速度因素所在.而且我倾向于同意小 n 使用@Frank 的解决方案和我的解决方案之间没有真正的速度差异。但是,一旦 n >10000,在 data.table 之外使用 lapply 而不是在 for 循环之外使用 lapply 会显着提高速度。
  • @Frank 你能解释一下为什么我应该使用 lapply 来迭代 .SD 吗?我知道这两种方法可以工作,但我不知道哪个更好。我期待着您的回答。

标签: r data.table


【解决方案1】:

如果您只想使用 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]))

希望这会有所帮助,如果您需要我在此答案中添加任何其他内容,请告诉我。祝你好运!

【讨论】:

  • 是的,它在使用 data.tables 时一直对我有用。我认为它不适用于标准 data.frames。
【解决方案2】:

一个没有 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)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多