我正在创建一个使用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)
如果我在函数中使用
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
我应该坚持吗
DT <- foo(DT)
或eval
/ substitute
路线,或关于
data
如何加载数据集,即使不是很懒,我是否还不了解?
最佳答案
这与数据集或锁定无关-您可以简单地使用
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
关于r - 通过引用分配到加载的包装数据集中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15195220/