【问题标题】:Memory efficient way to modify a variable within a function在函数中修改变量的内存有效方法
【发布时间】:2023-04-03 05:57:01
【问题描述】:

问题

我想写一个函数,修改一个大矩阵的每一列,x

f = function(x){
    # do something to x
    # return x
}

因为 x 非常大,我想“就地”修改它,即不创建副本。但是,我的理解是,在 R 中,函数是“修改时复制”。换句话说,如果我在函数 f 中修改 x,R 将复制 x

建议的解决方案(更新:不起作用!有关详细信息,请参阅下面的答案。

因此,看来最好的解决办法是修改全局变量,即

f = function(x){
    x = deparse(substitute(x))
    x = get(x, envir = globalenv())
    # do something to x
}

问题

但是,SO 上的人们对于将全局变量传递给 R 中的函数非常消极。有些人甚至仅仅因为询问它而被否决。

我的问题是:在 R 中执行此类操作的最佳方法是什么?

【问题讨论】:

  • 我很确定您提出的解决方案仍会在 f 中创建一个副本,但我很想对其进行测试。
  • data.table 包。常规 R 函数中的赋值仍然会生成中间 temp 副本。避免这种情况的唯一方法是重新定义 [
  • 我很好奇哪些问题被否决了“将全局变量传递给函数” ...除了最严格的环境之外,这在所有环境中都是不可避免的。相反,我可以相信:通过违反词法范围从函数内部访问(甚至修改)全局变量,而不被传递。有时,纯函数式方法可能效率低下,但不受控制的副作用使调试和代码维护极其困难。不幸的是,正如@42- 所建议的那样,R 几乎完全是关于 ref-by-copy 和 copy-on-write,data.table 是一个值得注意的例外。
  • data.table 在这种情况下会有所帮助。例如:修改选择的列cols <- names(dt)[c(1, 5, 10)]; dt[, (cols) := lapply(.SD, function(x) x/mean(x)), .SDcols = cols]
  • @Tung,在您的解决方案中,我很好奇使用了多少内存?我的理解是 data.table 在内存中创建两个对象(原始数据表和均值表),然后用另一个替换一个?还是原始表中的每一列在计算出新的中心值后立即被替换?

标签: r memory memory-management global


【解决方案1】:

这里已经讨论过这个问题:

Pass an object to a function without copying it on change

您的第二种方法并不能真正解决问题。这是我用 mem_used() 的结果运行的测试

library(pryr)
mem_used()
#41.3 MB

x <- matrix(1:1000000000, ncol=1000)
mem_used()
#4.04GB


f2<- function(x){
  print(mem_used())
  x = deparse(substitute(x))
  print(mem_used())
  x = get(x, envir = globalenv())
  x<- x+1
  print(mem_used())
  x
}

x <- f2(x)
#4.04 GB
#4.04 GB
#12 GB
mem_used()
#8.04GB

【讨论】:

  • 很高兴知道。我将更新我的问题以反映这一点。谢谢!
猜你喜欢
  • 1970-01-01
  • 2012-04-26
  • 2014-03-25
  • 1970-01-01
  • 2016-05-23
  • 1970-01-01
  • 2012-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多