警告:';无效。检测到internal.selfref';向函数返回的data.table中添加列时
这似乎是警告:';无效。检测到internal.selfref';向函数返回的data.table中添加列时,r,data.table,R,Data.table,这似乎是freadbug,但我不确定 这个例子再现了我的问题。我有一个函数,读取data.table并在列表中返回它。我使用列表将其他结果分组到相同的结构中。这是我的代码: ff.fread <- function(){ dt = fread("x 1 2 ") list(dt=dt) } DT.f <- ff.fread()$dt 这与fread本身无关,而是调用list()并向其传递一个命名对象。我们可以通过执行以下操作来重新创建: require(data.t
fread
bug,但我不确定
这个例子再现了我的问题。我有一个函数,读取data.table并在列表中返回它。我使用列表将其他结果分组到相同的结构中。这是我的代码:
ff.fread <- function(){
dt = fread("x
1
2
")
list(dt=dt)
}
DT.f <- ff.fread()$dt
这与
fread
本身无关,而是调用list()
并向其传递一个命名对象。我们可以通过执行以下操作来重新创建:
require(data.table)
DT <- data.table(x=1:2) # name the object 'DT'
DT.l <- list(DT=DT) # create a list containing one data.table
y <- DT.l$DT # get back the data.table
y[, bla := 1L] # now add by reference
# works fine but warning message will occur
DT.l = list(DT=data.table(x=1:2)) # DT = a call, not a named object
y = DT.l$DT
y[, bla:=1L]
# works fine and no warning message
R制作的data.table
的任何副本(不是data.table
的copy()
)的问题在于,R在内部将truelength
参数设置为0,即使truelength(.)
函数仍将返回正确的结果。当通过引用:=
进行更新时,这无意中导致segfault,因为过度分配不再存在(或至少不再被识别)。这发生在<1.7.8版本中。为了克服这个问题,引入了一个名为.internal.selfref
的属性。您可以通过执行属性(DT)
来检查此属性
来自新闻(第1.7.8版):
o“克里斯崩溃”已修复。根本原因是,
keyArun的回答是一个很好的解释。R中list()
的具体功能与fread
无关,与list
有关,这里有一个简单的例子:dt=data.table(a=1);l=列表(dt);dt1=l[[1]];dt1[,b:=2]
注意,警告消息确实指出list()
复制命名输入。完整的警告消息现在已在中编辑。警告消息包含以下内容:`另外,在RYou're right中。我已经删除了ref.to标记
(尽管它只起了一小部分作用)。不过,我认为这足以说明问题。我认为这一警告指的是一个经常发生的案例。但只要复制发生(这不是通过实际的copy
函数),或者无论如何是无意的,那么,:=
必须正确复制才能通过引用进行更新(因为它的truelength将设置为0)…最后一件事,在您的示例中,如果我删除属性setattr(y',.internal.selfref',NULL)
,我仍然得到警告。我想这个属性不是真的被删除了,只是被隐藏了。阿伦非常感谢这个伟大的答案+如果我能的话,就给我10英镑!
ff <- function(){
list(dt=data.table(x=1:2))
}
DT <- ff()$dt
DT[,y:=1:2]
ff.fread <- function(){
dt = fread("x
1
2
")
dt
}
require(data.table)
DT <- data.table(x=1:2) # name the object 'DT'
DT.l <- list(DT=DT) # create a list containing one data.table
y <- DT.l$DT # get back the data.table
y[, bla := 1L] # now add by reference
# works fine but warning message will occur
DT.l = list(DT=data.table(x=1:2)) # DT = a call, not a named object
y = DT.l$DT
y[, bla:=1L]
# works fine and no warning message
tracemem(DT)
# [1] "<0x7fe23ac3e6d0>"
DT.list <- list(DT=DT) # `DT` is the named object on the RHS of = here
# tracemem[0x7fe23ac3e6d0 -> 0x7fe23cd72f48]:
SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot);
DT <- data.table(x=1:2) # internal selfref set
DT.list <- list(DT=DT) # copy made, address(DT.list$DT) != address(DT)
# and truelength would be affected.
DT.new <- DT.list$DT # address of DT.new != address of DT
# and it's not equal to the address pointed to by
# the attribute's 'prot' external pointer
# so a re-over-allocation has to be made by data.table at the next update by
# reference, and it warns so you can fix the root cause by not using list(),
# key<-, names<- etc.
> R.version.string
[1] "R version 3.0.2 (2013-09-25)"
> DT = data.table(a=1:3)
> address(DT)
[1] "0x1d70010"
> address(list(DT)[[1]])
[1] "0x21bc178" # different address => list() copied the data.table named DT
> data.table:::selfrefok(DT)
[1] 1
> data.table:::selfrefok(list(DT)[[1]])
[1] 0 # i.e. this copied DT is not over-allocated
> ans = list()
> ans$DT = DT # use $<- instead
> address(DT)
[1] "0x1d70010"
> address(ans$DT)
[1] "0x1d70010" # good, no copy
> identical(ans, list(DT=DT))
[1] TRUE
> data.table:::selfrefok(ans$DT)
[1] 1 # good, the list()-ed DT is still over-allocated ok