我是否需要在函数内将 copy() 与 data.table 对象一起使用?

Do I need to use copy() with data.table objects inside a function?

我是否需要在函数内部使用 copy() 以避免对输入进行意外修改data.table?

例如

myfun <- function(mydata) {   
     mydata[,newcolumn := .N,by=id]   
     setnames(mydata, "newcolumn", "Count")
     return(table(mydata$Count))
}

myfun <- function(mydata) {   
     temp <- copy(mydata)
     temp[,newcolumn := .N,by=id]   
     setnames(temp, "newcolumn", "Count")
     return(table(temp$Count))
}

或者将 data.table 传递给函数是否已经创建了一个副本,即使我使用 := 赋值?

@Henrik 到 的链接答案确实解释了回答您问题的所有细节。

您的示例函数的这个(修改后的)版本 修改传递的 data.table:

library(data.table)
dt <- data.table(id = 1:4, a = LETTERS[1:4])
myfun2 <- function(mydata) {   
  x <- mydata[, .(newcolumn = .N), by=id]
  setnames(x, "newcolumn", "Count")
  return(table(x$Count))
}
myfun2(dt)

这不会复制整个 data.table(这会浪费 RAM 和 CPU 时间),只会将聚合结果写入一个新的 data.table可以修改而没有副作用(=原始data.table没有变化)。

> str(dt)
Classes ‘data.table’ and 'data.frame':  4 obs. of  2 variables:
 $ id: int  1 2 3 4
 $ a : chr  "A" "B" "C" "D"

A data.table 总是通过对函数的引用传递,因此您必须小心不要修改它,除非您绝对确定要这样做。

data.table 包正是为这种高效的数据修改方式而设计的,无需通常的 "COW" ("copy on (first) write") 原则来支持高效的数据操作。

"Dangerous"修改adata.table的操作主要有:

  • :=赋值修改或新建列"in-place"
  • 所有 set* 函数

如果您不想修改 data.table,您可以仅使用行过滤器和列(选择)表达式(ijby等参数)。

如果您在第二个(或更高版本的)链中修改 "by ref",链接也会阻止对原始 data.frame 的修改:

myfun3 <- function(mydata) {
  # chaining also creates a copy 
  return(mydata[id < 3,][, a := "not overwritten outside"])
}

myfun3(dt)
# > str(dt)
# Classes ‘data.table’ and 'data.frame':    4 obs. of  3 variables:
# $ id: int  1 2 3 4
# $ a : chr  "A" "B" "C" "D"