data.table:使用矩阵更新data.table中的多个列

4
我该如何使用矩阵中的值更新data.table中的多个列?以下是一个最小工作示例,说明我所面临的问题:
library(data.table)
DT = data.table(expand.grid(1:3,1:3,1:3))
DF = expand.grid(1:3,1:3,1:3)
mat = matrix(seq(0, 80), 27, 3)

在一个 data.frame 的世界里,我会选择以下语法:
DF[,2:ncol(DF)] = mat[,2:ncol(DF)] #Data frame approach

类似于`data.table`语法的另一种写法会产生多个警告和非常奇怪的输出。
DT[,2:ncol(DF) := mat[,2:ncol(DF)], with=FALSE] #Data table approach

这显然是有毛病的-因为警告表明矩阵实际上已被扁平化了。警告消息:

1: In `[.data.table`(DT, , `:=`(2:ncol(DF), mat[, 2:ncol(DF)]), with = FALSE) :
  2 column matrix RHS of := will be treated as one vector

请注意,DT[,3:ncol(DT) - 1] 是一个常见的严重错误 - 您正在从 (3:ncol(DT)) 中的每个数字中减去1,而不仅仅是 ncol(DT) 本身。 - Señor O
1
我建议阅读入门页面上的小品文,特别是参考语义小品文。:=的右侧需要一个列表。强制转换是不可避免的。 - Arun
2个回答

9

你需要将RHS转换成一个list,而一个简单的方法是使用as.data.table

DT[, 2:ncol(DT) := as.data.table(mat[,2:ncol(DT)])]

with在这里并不必要,因为左侧已经自动推断为列号。


我很好奇当你说这种类型的赋值不是优化时,你指的是什么。使用:=语法进行赋值是否通常被优化,而这种特定用法无法实现优化?请注意,我有点数据表新手。 - bgoldst
1
@bgoldst 我的帖子已经被编辑了,所以那一行不再存在,但是我指的“优化”是非技术意义上的。:= 的设计初衷是用于将特定列名分配给特定对象名,并在右侧使用它们。类似这样的代码:data[, c("Speed", "Time") := list(dt2$Distance/dt2$Time, dt2$Time)] - Señor O

3

当分配给多个列时,应将这些列收集到列表中:

idx <- 2:ncol(DT)
DT[,idx] <- lapply(idx, function(col) mat[,col])

这种语法对于一个数据框架也适用。在数据表中,这是非标准的(其中set:=是惯用语),但仍具有通过引用修改DT的好处。

惯用的:=方法是:

DT[,(idx) := lapply(idx, function(col) mat[,col])]

所以在某种程度上,我们回到了data.frame语法。只是我们要索引的项应该是一个列表? - sriramn
还是只需要 DT[,(idx) := data.table(mat[,idx])],对吧? - David Arenburg
@sriramn 是的。虽然我会倡导使用 := 版本(我刚刚添加到答案中),因为它是惯用语,因此在其他 data.table 代码中更容易阅读。请参见 Arun 在您的问题上的评论,以获取一个好的起点。 - Frank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接