mne*_*nel 18 r data.table
我正在创建一个使用a data.table
作为数据集的包,并有一些函数,通过引用使用:=
.
我已经构建了一个简单的包来演示我的 problem
library(devtools)
install_github('foo','mnel')
Run Code Online (Sandbox Code Playgroud)
它包含两个功能
foo <- function(x){
x[, a := 1]
}
fooCall <- function(x){
eval(substitute(x[, a :=1]),parent.frame(1))
}
Run Code Online (Sandbox Code Playgroud)
和DT
使用创建的数据集(不是延迟加载)
DT <- data.table(b = 1:5)
save(DT, file = 'data/DT.rda')
Run Code Online (Sandbox Code Playgroud)
当我安装这个软件包时,我的理解是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
Run Code Online (Sandbox Code Playgroud)
如果我使用更多 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)
Run Code Online (Sandbox Code Playgroud)
如果我在函数内使用eval
和substitute
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
Run Code Online (Sandbox Code Playgroud)
我应该坚持下去
DT <- foo(DT)
或eval
/ substitute
路线,或data
加载数据集的方式,即使不是懒惰的吗?Sim*_*nek 10
这与数据集或锁定无关 - 您只需使用即可重现它
DT<-unserialize(serialize(data.table(b = 1:5),NULL))
foo(DT)
DT
Run Code Online (Sandbox Code Playgroud)
我怀疑这与data.table
必须在第一次访问时在对象内部重新创建extptr 的事实有关DT
,但是它在副本上这样做,所以它无法在全局环境中与原始文件共享修改.
[来自马修]完全正确.
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
或者,不要传入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
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是使用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)
}
Run Code Online (Sandbox Code Playgroud)