要求 r 函数在全局环境中使用对象而不是对象的副本

Posted

技术标签:

【中文标题】要求 r 函数在全局环境中使用对象而不是对象的副本【英文标题】:Require r function to use objects in global environment rather than copy of object 【发布时间】:2018-05-04 09:45:39 【问题描述】:

我(也许是无知)对 R 的理解是函数会在内存中创建对象的临时副本。即使全局环境中的对象太大而无法复制,我如何仍然使用函数来简化代码?还是建议只对大对象的必要部分进行子集化以供函数操作?

例子

# load two objects with 10 million rows and 500 columns
big.object.1 <- readRDS(file = "previously.created.dataframe.1")
big.object.2 <- readRDS(file = "previously.created.dataframe.2")

# method 1 with memory use of ~xMB?
big.object.1$recoded.column <- ifelse(big.object.1$old.column > 0,
                                      big.object.1$recoded.column * 2,
                                      big.object.1$recoded.column * 0.5)

# method 2 with memory use of ~2xMB?
new.column_function <- function(data, old.col, recoded.col) 
  data[recoded.col] <- ifelse(data[old.col] > 0,
                                data[recoded.col] * 2,
                                data[recoded.col] * 0.5)


new.column_function(data = big.object.1, 
                    recoded.col = 400, 
                    new.col = 401)

当代码很复杂但没有函数但内存是函数的问题时,最佳做法是什么?如何避免复制大对象?

【问题讨论】:

您可以尝试data.table,当您的data.frame 存在内存问题时。:=,快速添加、删除和更新列子集,参考。 @incas56,你能举一个简单的例子作为答案吗?甚至可能将 data.frame 转换为 data.table,然后按照上面指定的方式操作 data.table?谢谢。 【参考方案1】:

您可以使用&lt;&lt;-(而不是&lt;-)在函数内访问全局环境中的对象

new.column_function <- function(old.col, recoded.col) 

  ind <- big.object[old.col] > 0

  # Do this 
  big.object[recoded.col] <<- ifelse(ind, big.object[recoded.col][ind] * 2,
                                      big.object[recoded.col][ind] * 0.5) 

  # OR do this
  big.object[recoded.col][ind] <<- big.object[recoded.col][ind] * 2
  big.object[recoded.col][!ind] <<- big.object[recoded.col][!ind] * 0.5

  # Don't think this behaves in the intended way...
  #         ifelse(big.object[old.col] > 0,
  #                                big.object[recoded.col] * 2,
  #                                big.object[recoded.col] * 0.5)

我不知道这是否比使用data.table 更好。

【讨论】:

假设我有 big.object.1 和 big.object.2。因此,我认为我需要一个函数参数来指定哪个对象(例如 function(big.object, old.col, recoded.col) )。 如果我调用 new.column_function(big.object.2, 400, 401) 并在函数内部使用 ,这是否仍会避免复制 big.object.2?或者您可能建议 big.object.1 使用一个函数,而 big.object.2 使用第二个函数? new.column_function(big.object.2, 400, 401) 将创建big.object.2 的副本。顺便说一句,您的 ifelse 是错误的。 我觉得你使用ifelse的方式有问题。尝试编辑后的解决方案中的一种方法。 如果您有类似的几个大对象要传递,然后尝试使用指标变量,然后执行if() else 确定要工作的对象。将名称作为刺痛传递也可以。【参考方案2】:

您可以尝试使用函数getassign 仅将对象的名称提供给函数而不是整个对象

new.column_function <- function(nameOfData, old.col, recoded.col) 
  get(nameOfData)[recoded.col] <- ifelse(data[old.col] > 0,
                                data[recoded.col] * 2,
                                data[recoded.col] * 0.5)

在这种情况下,nameOfData 是一个值为 big.object.1 的字符串,例如

【讨论】:

以上是关于要求 r 函数在全局环境中使用对象而不是对象的副本的主要内容,如果未能解决你的问题,请参考以下文章

获取在 R 的全局环境中加载的函数列表 [重复]

R编辑在父环境中定义的全局对象

使用 .onLoad() 将对象加载到 R 包中的全局环境中

JavaScript this

JS 中的 this 总结

.net XML 序列化 - 存储引用而不是对象副本