2014-09-26 121 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