通过引用分配到已加载的包数据集中

时间:2013-03-04 05:36:53

标签: r data.table

我正在创建一个使用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 <- foo(DT)eval / substitute路线或
  2. 是否有一些我不了解data如何加载数据集,即使不是懒惰?

2 个答案:

答案 0 :(得分:10)

这与数据集或锁定无关 - 您只需使用

即可重现它
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

答案 1 :(得分:4)

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

# 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)



}