我存储了 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"
我的问题有两个:
- 为什么不
names1 <- names(DT)
创建data.table
的副本的名字?在其他情况下,我们会明确警告<-
创建data.table
的副本和data.frame
names1 <- names(DT)
之间有什么区别和names2 <- c(names(DT))
?
最佳答案
更新:现已添加到 ?copy
的文档中在1.9.3版本中。来自 NEWS :
<小时/>
- Moved
?copy
to it's own help page, and documented thatdt_names <- copy(names(DT))
is necessary fordt_names
to be not modified by reference as a result of updatingDT
by reference (ex: adding a new column by reference). Closes #512. Thanks to Zach for this SO question and user1971988 for this SO question.
你的第一个问题的一部分让我有点不清楚你对 <-
的真正含义。运算符(至少在 data.table
的上下文中),尤其是以下部分:在其他情况下,我们明确警告 <- 创建 data.tables 和 data.frames 的副本。 p>
因此,在回答您的实际问题之前,我将在这里简要介绍一下。如果是data.table
一个<-
(赋值)仅仅不足以复制 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
。甚至是truelength
的names1
是 100(默认分配在 data.table
中,请检查 ?alloc.col
)。
truelength(names1)
# [1] 100
基本上,作业 names1 <- names(dt)
似乎是通过引用发生的。即names1
指向与 dt 的列名指针相同的位置。
回答你的第二个问题:命令c(.)
似乎创建了一个副本,因为没有检查连接操作导致的内容结果是否不同。也就是说,因为c(.)
操作可以更改向量的内容,它会立即导致“复制”而不检查内容是否被修改。
关于r - 为什么 data.table 会通过引用更新名称(DT),即使我分配给另一个变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15913417/