为什么data.table通过引用更新名称(DT),即使我分配给另一个变量?

时间:2013-04-09 22:04:50

标签: r data.table

我已将data.table的名称存储为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")

但是,这不是普通的字符向量。这是一个神奇的角色矢量!当我向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名称的副本?在其他情况下,我们会明确警告<-创建data.tabledata.frame s的副本。
  2. names1 <- names(DT)names2 <- c(names(DT))之间的区别是什么?

1 个答案:

答案 0 :(得分:38)

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

  
      
  1. ?copy移至其自己的帮助页面,并记录dt_names <- copy(names(DT))dt_names所必需的,因为通过引用更新DT<-不会被引用修改(例如:通过引用添加新列)。关闭#512。感谢Zach for this SO question和user1971988 for this SO question
  2.   

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

因此,在回答您的实际问题之前,我将在此处简要介绍一下。如果<- 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 命令明确提及它。

names(dt) <- .

从CauchyDistributedRV,我明白你的意思是导致警告的作业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

在这里,您看到它们指向相同的内存位置truelength。即使names1的{​​{1}}为100(默认情况下会在data.table中分配,也请检查?alloc.col)。

truelength(names1)
# [1] 100

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

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