46

我已将 a 的名称存储data.table为 a vector

library(data.table)
set.seed(42)
DT <- data.table(x = runif(100), y = runif(100))
names1 <- names(DT)

据我所知,这是一个普通的香草字符向量:

str(names1)
# chr [1:2] "x" "y"

class(names1)
# [1] "character"

dput(names1)
# c("x", "y")

但是,这不是普通的字符向量。这是一个神奇的字符向量!当我向 my 添加新列时data.table,此向量会更新!

DT[ , z := runif(100)]
names1
# [1] "x" "y" "z"

我知道这与如何:=通过分配进行更新有关,但这对我来说仍然很神奇,因为我希望<-复制名称data.table

我可以通过将名称包含在以下内容中来解决此问题c()

library(data.table)
set.seed(42)
DT <- data.table(x = runif(100), y = runif(100))

names1 <- names(DT)
names2 <- c(names(DT))
all.equal(names1, names2)
# [1] TRUE

DT[ , z := runif(100)]
names1
# [1] "x" "y" "z"

names2
# [1] "x" "y"

我的问题有两个:

  1. 为什么不names1 <- names(DT)创建名称的副本data.table?在其他情况下,我们被明确警告会创建s 和s 的<-副本。data.tabledata.frame
  2. names1 <- names(DT)和有什么区别names2 <- c(names(DT))
4

1 回答 1

44

更新:现在添加到?copy版本 1.9.3 的文档中。来自新闻

  1. 移动?copy到它自己的帮助页面,并记录dt_names <- copy(names(DT))dt_names由于引用更新而不能通过引用修改DT(例如:通过引用添加新列)。关闭#512。感谢 Zach 提出这个 SO 问题,感谢 user1971988 提出这个 SO 问题

您的第一个问题的一部分让我有点不清楚您对运算符的真正含义<-(至少在 的上下文中data.table),尤其是以下部分:在其他情况下,我们明确警告 <- 创建副本,两个.tables 和 data.frames。

因此,在回答您的实际问题之前,我将在这里简要介绍一下。在data.tablea <-(assignment) 的情况下,仅仅复制 a是不够data.table的。例如:

DT <- data.table(x = 1:5, y= 6:10)
# assign DT2 to DT
DT2 <- DT # assign by reference, no copy taken.
DT2[, z := 11:15]
# DT will also have the z column

如果要创建copy,则必须使用copy命令明确提及它。

DT2 <- copy(DT) # copied content to DT2
DT2[, z := 11:15] # only DT2 is affected

从 CauchyDistributedRV,我了解您的意思是names(dt) <- .会导致警告的分配。我就这样吧。


现在,回答你的第一个问题:它的行为似乎names1 <- names(DT)也相似。直到现在我才想到/知道这一点。该.Internal(inspect(.))命令在这里非常有用:

.Internal(inspect(names1))
# @7fc86a851480 16 STRSXP g0c7 [MARK,NAM(2)] (len=2, tl=100)
#   @7fc86a069f68 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "x"
#   @7fc86a0f96d8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "y"

.Internal(inspect(names(DT)))
# @7fc86a851480 16 STRSXP g0c7 [MARK,NAM(2)] (len=2, tl=100)
#   @7fc86a069f68 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "x"
#   @7fc86a0f96d8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "y"

在这里,您会看到它们指向相同的内存位置@7fc86a851480。甚至truelengthofnames1也是 100(默认情况下分配在 中data.table,检查?alloc.col一下)。

truelength(names1)
# [1] 100

所以基本上,分配names1 <- names(dt)似乎是通过引用发生的。也就是说,names1指向与 dt 的列名指针相同的位置。

回答您的第二个问题:该命令c(.)似乎创建了一个副本,因为没有检查由于连接操作导致的内容结果是否不同。也就是说,由于c(.)操作可以改变向量的内容,它会立即导致“复制”,而不检查内容是否被修改。

于 2013-04-09T22:24:15.007 回答