在函数内部使用setDT

时间:2014-09-26 22:31:35

标签: r data.table

我正在编写一个函数,除其他外,它将输入强制转换为data.table。

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复制(或已手动创建)   使用结构()或类似的)。避免键&lt; - ,名称&lt; - 和attr&lt; - 哪个   在R当前(并且奇怪地)可以复制整个data.table。使用套装*   语法而不是复制:?set,?setnames和?setattr。也,   在R&lt; = v3.0.2中,list(DT1,DT2)复制了整个DT1和DT2(R&#39; s list()   用于复制命名对象);如果是,请升级到R&gt; 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)

这是正确的方法吗?

1 个答案:

答案 0 :(得分:16)

好问题!警告消息应该说: ...并通过采用整个表的副本来修复... 。将解决此问题。

setDT做了两件事:

  • 将课程设置为data.table / data.frame
  • list
  • 使用alloc.col过度分配列(以便:=可以直接使用)

如果输入不是data.table,则第二步需要浅拷贝。这就是为什么我们值重新分配给它的环境中的符号(setDT的父框架)。但setDT的父框架是您的函数f()。因此,函数中的setDT(df)已经顺利进行,但是驻留在全局环境中的df只会更改它的类,而不会过度分配(因为浅层副本会切断链接)。

在下一步中,:=会再次检测到这些和浅层副本过度分配

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

非常感谢!