2014-09-26 118 views
12

我正在写一个函数,其中包括强制输入到data.table中。在函数中使用setDT

library(data.table) 
df <- data.frame(id = 1:10) 
f <- function(df){setDT(df)} 
f(df) 
df[, temp := 1] 

然而,最后一个命令输出以下警告:

警告消息:在[.data.table(DF,:=(温度,1)):无效 .internal.selfref检测并通过固定取整个 表的副本,以便:=可以通过引用添加此新列。在较早的 点,此data.table已被R复制(或已使用structure()或类似方法手动创建 )。避免密钥< - ,名称< - 和attr < - 其中 在R目前(和奇怪)可能会复制整个data.table。使用set * 语法来避免复制:?set,?setnames和?setattr。同样, 在R < = v3.0.2中,列表(DT1,DT2)复制了整个DT1和DT2(R的列表() 用于复制命名对象);请升级到R> v3.0.2,如果是 咬。如果此消息无效,请报告给datatable-help ,以便修复根本原因。

我使用的是data.table和R 3.1.1的v1.9.3。这是否意味着df在某个时候被复制?如何避免此警告?

编辑: setDT的代码实际上使用NSE。所以这似乎工作:

df1 <- data.frame(id = 1:10) 
f <- function(df){eval(substitute(setDT(df)),parent.frame())} 
f(df1) 
df1[, temp := 1] 

看来我可以在功能f内做其他的东西用df像

df1 <- data.frame(id = 1:10) 
f <- function(df){ 
     eval(substitute(setDT(df)),parent.frame()) 
     df[, temp := 1] 
     } 
f(df1) 

这是做正确的方式?

回答

16

伟大的问题!警告消息应该说:...并通过采取修复整个表的副本...。将解决这个问题。

setDT做两两件事:

  • data.frame/list
  • 使用alloc.col设置类到data.table过度分配的列(使得:=可直接使用)

而如果输入不是data.table,则第2步需要浅拷贝。这就是为什么我们将赋值为的值返回到它的环境中的符号(setDT的父框架)。但setDT的父框架是您的功能f()。因此,你函数中的setDT(df)已经顺利通过了,但驻留在全局环境中的df只会改变它的类,而不是过度分配(因为浅层副本切断了链接)。

并且在下一步中,:=检测到并且再次浅拷贝到过度分配

到目前为止,想法是使用setDT将其提供给函数前转换为data.tables 之前。但我希望这些案例得到解决(会看一看)。

感谢一大堆!

+0

谢谢。至少在我的情况下,要求用户在使用函数之前使用setDT是有道理的。 – Matthew 2014-09-29 14:45:21

+0

有趣。那么'data.table'能够通过引用添加列的方式是分配一个较长的列表,然后将列添加到较长的列表中? – stanekam 2014-09-30 16:13:30

+0

@iShouldUseAName,它过度分配,是的。检查[这篇文章](http://stackoverflow.com/a/24476425/559784)(和链接那里)*稍微更详细的博览会。 – Arun 2014-09-30 18:32:15