通过引用分配到加载的包数据集中 [英] assigning by reference into loaded package datasets

查看:8
本文介绍了通过引用分配到加载的包数据集中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am in the process of creating a package that uses a data.table as a dataset and has a couple of functions which assign by reference using :=.

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

I have built a simple package to demonstrate my 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,使用

and a dataset (not lazy loaded) DT, created using

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

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

When I install this package, my understanding is that foo(DT) should assign by reference within 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)

如果我在函数中使用 evalsubstitute

If I use eval and substitute within the function

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 如何加载数据集,即使不是懒惰,我是否有什么不明白的地方?
  1. DT <- foo(DT) or the eval/substitute route, or
  2. Is there something I'm not understanding about how data loads datasets, even when not lazy?

推荐答案

这与数据集或锁定无关 - 您可以简单地使用它来重现它

This has nothing to do with datasets or locking -- you can reproduce it simply using

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

我怀疑这与 data.table 必须在第一次访问 DT 时在对象内重新创建 extptr 的事实有关,但它正在这样做以此类推,因此无法在全局环境中与原始版本共享修改.

I suspect it has to do with the fact that data.table has to re-create the extptr inside the object on the first access on DT, but it's doing so on a copy so there is no way it can share the modification with the original in the global environment.

[来自马修]正是.

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 中的一些固定名称表.

Or, don't pass DT into the function, just refer to it directly. Use data.table like a database: a few fixed name tables in .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

这篇关于通过引用分配到加载的包数据集中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆