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

R 通过引用分配到加载的包数据集中,r,data.table,R,Data.table,我正在创建一个包,该包使用data.table作为数据集,并具有两个函数,这些函数使用:=通过引用进行分配 我构建了一个简单的包来演示我的问题 library(devtools) install_github('foo','mnel') 它包含两个函数 foo <- function(x){ x[, a := 1] } fooCall <- function(x){ eval(substitute(x[, a :=1]),parent.frame(1)) } 当我安

我正在创建一个包,该包使用
data.table
作为数据集,并具有两个函数,这些函数使用
:=
通过引用进行分配

我构建了一个简单的包来演示我的
问题

 library(devtools)
 install_github('foo','mnel')
它包含两个函数

foo <- function(x){
  x[, a := 1]
}
fooCall <- function(x){
  eval(substitute(x[, a :=1]),parent.frame(1))
} 
当我安装这个软件包时,我的理解是
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
如果我使用更多
正确的

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)
我应该坚持吗


  • DT这与数据集或锁定无关——只需使用

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


    另一种解决方案是使用
    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)
    
    
    
    }
    
    #从对`data()的调用中获取环境`
    
    env从未尝试通过引用更新包中的数据!但是,如果数据包是密封的,那么数据包中的数据不应该是只读的吗?在这里末尾键入
    DT
    并不意味着它是通过引用分配的,是吗?DT可能被复制到了
    .GlobalEnv
    ,也可能是它被更新的地方。顺便说一句,TraceM
    报告了R本身的复制。不太可能捕捉到data.table所做的复制,例如第一次过度分配时,因为从技术上讲,这不是一个完美的复制,而是一个过度分配(虽然是浅拷贝而不是深拷贝)。也许可以尝试对包中的数据对象执行
    alloc.col
    ,看看会发生什么。@MatthewDowle我认为数据(DT)在全局环境中创建副本时,延迟加载可能意味着数据集被锁定。我不是在试图更新包中的副本,而是在示例/渐晕图中使用数据集。我不熟悉
    data()
    ,但这听起来不错。但是R正在创建它(不是data.table),也就是说,这是R的
    data()
    命令,它不知道过度分配。与加载()data.table时类似,在第一个
    :=
    添加新列之前,不会过度分配数据表。Does
    library(foo);数据(DT);alloc.col(DT);foo(DT)
    工作?Matthew:但是请注意,
    alloc.col()
    在函数内部同样不起作用(出于上述相同的原因)-您确实需要一些不试图伪造引用的东西-例如,如果需要通过引用将列添加到未序列化的data.table,那么有效的是
    DT,我认为这只是一个问题,在函数中,并且该表名事先未知(即需要通过函数参数传入)。我想不出一个例子,在非序列化之后直接调用
    alloc.col(DT)
    是不可能的,但在实践中也需要这样做。我倾向于像使用数据库一样使用data.table;i、 e.GlobalEnv中的几个大型固定名称表。请参阅“新建编辑”。@MatthewDowle(和Simon)--感谢您的指点,我可以看出您的第二个示例与我的想法有些相似,即构造适当的调用,并在正确的父环境中对其进行评估。(
    fooCall
    在我的问题中)+1有趣。我想知道是否应该增强
    alloc.col
    以同时接受字符向量?然后它可以包装
    load()
    调用。我认为您不需要
    数据。表:
    前缀为
    alloc。col
    已导出并供用户使用。@MatthewDowle,关于
    数据的要点很好。表:
    已修复,并修改为提前知道
    加载结果的特定情况
    alloc.col
    可能还需要一个环境参数。好主意。增强
    alloc.col
    现在已存档。
    DT<-unserialize(serialize(data.table(b = 1:5),NULL))
    foo(DT)
    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
    
    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 <- 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
    
    # 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)
    
    
    
    }