23

仍然理解这个很棒的包......有人可以解释一下这个错误的原因吗?谢谢!

library(data.table)

DT <- data.table(id   = LETTERS,
                 var1 = rnorm(26),
                 var2 = rnorm(26))

> DT[2, list(var1, var2)]
            var1          var2
1: -0.8628479332 -0.2367492928
> DT[2, c(var1, var2)]
[1] -0.8628479332 -0.2367492928
> 
> DT[2, list(var1, var2)] <- DT[8, list(var1, var2)]
Error in `[<-.data.table`(`*tmp*`, 2, list(var1, var2), value = list(var1 = -0.394006912428776,  : 
  object 'var1' not found
> DT[2, c(var1, var2)] <- DT[8, c(var1, var2)]
Error in `[<-.data.table`(`*tmp*`, 2, c(var1, var2), value = c(-0.394006912428776,  : 
  object 'var1' not found
4

1 回答 1

40

首先,建议使用:=而不是[<-为了效率。主要[<-是为了向后一致性提供的。因此,我将首先说明如何有效地使用:=来获得您所追求的。:=是通过引用分配(它更新 data.table 而不复制数据,因此非常快)。

require(data.table)
DT <- data.table(x = 1:5, y = 6:10, z = 11:15)

假设您要将“y”的第 2 行更改为“y”的第 5 行:

DT[2, y := DT[5, y]] 

或等效地

DT[2, `:=`(y = DT[5, y])]

假设您要将“y”和“z”的第 2 行更改为第5行中相应条目的第 2 行,则:

DT[2, c("y", "z") := as.list(DT[5, c(y, z)])]

或等效地

DT[2, `:=`(y = DT[5, y], z = DT[5, z])]

现在只是为了向您展示如何分配 using [<-(虽然显然不推荐),它可以按如下方式完成:

DT <- data.table(x = 1:5, y = 6:10, z = 11:15)
DT[1, c("y", "z")] <- as.list(DT[5, c(y, z)])

或者等效地,您也可以传递列号:

DT[1, 2:3] <- as.list(DT[5, c(y, z)])

希望这可以帮助。


编辑 1

至于为什么会出现错误:

首先,RHS 必须是一个列表,[<-data.table如果它有超过 1 个要分配的列。

其次,j左侧的参数<-不会在 data.table 的环境中进行评估。因此,它需要知道值j是什么。并且由于您提供var1and var2(没有使它们成为字符向量的双引号),因此它被理解为一个变量。因此,它检查变量var1和其父环境中的变量,这是找不到它们的全局环境,因此您会收到错误消息。例如:这样做:var2<-

y <- "y"
z <- "z"
# And now try your second case: 
DT[2, c(y, z)] <- as.list(DT[5, c(y, z)])
# the left side takes values from the assignments you made above
# the right side y and z are evaluated within the environment of your data.table
# and so it sees the columns y and z as variables and their values are picked accordingly

第三,该[<-data.table函数只接受atomic(向量)类型的j参数。因此,DT[2, list(var1, var2)] <- DT[8, list(var1, var2)]如果您以正确的方式进行操作,您的第一个作业仍然会出错,即:

y <- "y"
z <- "z"
DT[2, list(y, z)] <- as.list(DT[5, c(y, z)])

# Error in `[<-.data.table`(`*tmp*`, 2, list(y, z), value = list(10L, 15L)) : 
#   j must be atomic vector, see ?is.atomic

希望这可以帮助。


编辑 2

只是为了说明你的 data.table 的副本是在你做的时候做的[<-,而不是什么时候做:=的,

DT <- data.table(x = 1:5, y = 6:10, z = 11:15)
tracemem(DT)
# [1] "<0x7fbefb89b580>"

DT[1, c("y", "z") := list(100L, 110L)]
tracemem(DT)
# [1] "<0x7fbefb89b580>"

DT[2, c("y", "z")] <- list(200L, 201L)
# tracemem[0x7fbefacc4fa0 -> 0x7fbefd297838]: # copied, inefficient
于 2013-05-12T11:33:59.703 回答