【问题标题】:assigning by reference into loaded package datasets通过引用分配到加载的包数据集中
【发布时间】:2013-02-18 04:00:30
【问题描述】:

我正在创建一个包,该包使用data.table 作为数据集,并具有几个使用:= 通过引用分配的函数。

我已经构建了一个简单的包来演示我的problem

 library(devtools)
 install_github('foo','mnel')

它包含两个功能

foo <- function(x){
  x[, a := 1]
}
fooCall <- function(x){
  eval(substitute(x[, a :=1]),parent.frame(1))
} 

和一个数据集(非延迟加载)DT,使用

创建
DT <- data.table(b = 1:5)
save(DT, file = 'data/DT.rda')

当我安装这个包时,我的理解是foo(DT) 应该在DT 中通过引用分配。

 library(foo)
 data(DT)
 foo(DT)
   b a
1: 1 1
2: 2 1
3: 3 1
4: 4 1
5: 5 1

# However this has not assigned by reference within `DT`

DT
   b
1: 1
2: 2
3: 3
4: 4
5: 5

如果我使用更多correct

tracmem(DT)
DT <- foo(DT)
# This works without copying
DT 
 b a
1: 1 1
2: 2 1
3: 3 1
4: 4 1
5: 5 1
untracemem(DT)

如果我在函数中使用evalsubstitute

fooCall(DT)
   b a
1: 1 1
2: 2 1
3: 3 1
4: 4 1
5: 5 1
# it does assign by reference 
DT
   b a
1: 1 1
2: 2 1
3: 3 1
4: 4 1
5: 5 1

我应该坚持吗

  1. DT &lt;- foo(DT)eval/substitute 路由,或
  2. 关于data 如何加载数据集,即使不是懒惰,我是否有什么不明白的地方?

【问题讨论】:

  • 从未尝试过通过引用更新包中的数据!但是,如果包中的数据被密封,难道它们不应该是只读的吗?在此处最后键入DT 并不意味着它是通过引用分配的,不是吗? DT 可能已被复制到 .GlobalEnv,并且可能已被更新。
  • 顺便说一句 tracemem R 自己报告重复。不太可能捕获 data.table 所做的副本,例如在第一次过度分配时,因为从技术上讲这不是完美的复制,而是过度分配(尽管是浅拷贝而不是深拷贝)。
  • 也许在包中的数据对象上尝试alloc.col,看看会发生什么。
  • @MatthewDowle 我认为 data(DT) 在全局环境中创建了一个副本,延迟加载可能意味着数据集被锁定。我不是在尝试更新包中的副本,而是在示例/小插图中使用数据集。
  • 我不熟悉data(),但是是的,这听起来没有错。但是 R 正在创建它(不是 data.table),即 R 的 data() 命令不知道过度分配。与load() data.table 类似,直到第一个:= 添加新列之前,它不会被过度分配。 library(foo); data(DT); alloc.col(DT); foo(DT) 有效吗?然后我们可以从那里开始。

标签: r data.table


【解决方案1】:

另一种解决方案是使用inst/extdata 保存rda 文件(其中将包含任意数量的data.table 对象)并在data 子目录中拥有一个文件DT.r

# get the environment from the call to `data()`
env <- get('envir', parent.frame(1))
# load the data
load(system.file('extdata','DT.rda', package= 'foo'), envir = env)
# overallocate (evaluating in correct environment)
if(require(data.table)){
# the contents of `DT.rda` are known, so write out in full
  evalq(alloc.col(DT), envir = env)

}
# clean up so `env` object not present in env environment after calling `data(DT)`
rm(list = c('env'), envir = env)



}

【讨论】:

  • +1 有趣。我想知道是否应该增强 alloc.col 以接受字符向量?然后它可以包装load() 调用。我认为您不需要 data.table:: 前缀,因为 alloc.col 已导出并供用户使用。
  • @MatthewDowle,关于data.table:: 的好点已修复,并修改为提前知道load 结果的特定情况。 alloc.col 可能还需要环境参数。
  • 好主意。 FR#2595 增强 alloc.col 现已归档。
【解决方案2】:

这与数据集或锁定无关——您可以简单地使用复制它

DT<-unserialize(serialize(data.table(b = 1:5),NULL))
foo(DT)
DT

我怀疑这与data.table 必须在第一次访问DT 时在对象内重新创建 extptr 的事实有关,但它是在副本上这样做的,所以它无法共享在全局环境中与原来的修改。


[来自马修]正是。

DT<-unserialize(serialize(data.table(b = 1:3),NULL))
DT
   b
1: 1
2: 2
3: 3
DT[,newcol:=42]
DT                 # Ok. DT rebound to new shallow copy (when direct)
   b newcol
1: 1     42
2: 2     42
3: 3     42

DT<-unserialize(serialize(data.table(b = 1:3),NULL))
foo(DT)
   b a
1: 1 1
2: 2 1
3: 3 1
DT                 # but not ok when via function foo()
   b
1: 1
2: 2
3: 3


DT<-unserialize(serialize(data.table(b = 1:3),NULL))
alloc.col(DT)      # alloc.col needed first
   b
1: 1
2: 2
3: 3
foo(DT)
   b a
1: 1 1
2: 2 1
3: 3 1
DT                 # now it's ok
   b a
1: 1 1
2: 2 1
3: 3 1

或者,不要将DT传入函数中,直接引用即可。像数据库一样使用data.table.GlobalEnv 中的一些固定名称表。

DT <- unserialize(serialize(data.table(b = 1:5),NULL))
foo <- function() {
   DT[, newcol := 7]
}
foo()
   b newcol
1: 1      7
2: 2      7
3: 3      7
4: 4      7
5: 5      7
DT              # Unserialized data.table now over-allocated and updated ok.
   b newcol
1: 1      7
2: 2      7
3: 3      7
4: 4      7
5: 5      7

【讨论】:

  • @Matthew: 但请注意alloc.col() 将同样在函数内部工作(出于上述相同的原因) - 你真的需要一些不会试图伪造引用的东西- 例如有效的是DT &lt;- DT[TRUE]。这一点在 data.table 文档中值得一提,因为反序列化 data.table 对象会产生一个难以追踪的问题(而且它一直在发生 - 在工作区、包等中)。
  • 只有一个问题,我相信,如果需要通过引用未序列化的 data.table 来添加列,从函数内部,并且该表名事先不知道(即需要通过函数参数传入)。我想不出一个例子,在反序列化之后直接调用alloc.col(DT) 是不可能的,但在实践中也需要。我倾向于像数据库一样使用 data.table;即 .GlobalEnv 中的一些大型固定名称表。请查看新的编辑。
  • @MatthewDowle(和 Simon)——感谢您的指点,我可以看到您的第二个示例与我构建适当调用并在正确的父环境中评估它的想法有些相似。 (fooCall 在我的问题中)
猜你喜欢
  • 1970-01-01
  • 2011-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 2016-07-22
  • 1970-01-01
  • 2019-02-24
相关资源
最近更新 更多