这是我在@sds回答这个问题时的一个观察结果.
首先,让我打开跟踪消息data.table:
options(datatable.verbose = TRUE)
dt <- data.table(a = c(rep(3, 5), rep(4, 5)), b=1:10, c=11:20, d=21:30, key="a")
Run Code Online (Sandbox Code Playgroud)
现在,假设有人希望得到按列分组的所有列的总和a,那么,我们可以这样做:
dt.out <- dt[, lapply(.SD, sum), by = a]
Run Code Online (Sandbox Code Playgroud)
现在,假设我还要添加属于每个组的条目数dt.out,那么我通常按引用分配它,如下所示:
dt.out[, count := dt[, .N, by=a][, N]]
# or alternatively
dt.out[, count := dt[, .N, by=a][["N"]]]
Run Code Online (Sandbox Code Playgroud)
在这个通过引用的赋值中,其中一个消息data.table产生的是:
RHS for item 1 has been duplicated. Either NAMED vector or recycled list RHS.
Run Code Online (Sandbox Code Playgroud)
这是来自data.table的源目录中的文件的消息assign.C.我不想在这里粘贴相关的片段,因为它大约有18行.如有必要,只需发表评论即可粘贴代码.dt[, .N, by=a][["N"]]只是给[1] 5 5.所以,它不是一个named vector.我不明白recycled listRHS中的这个是什么..
但如果我这样做:
dt.out[, `:=`(count = dt[, .N, by=a][, N])]
# or equivalently
dt.out[, `:=`(count = dt[, .N, by=a][["N"]])]
Run Code Online (Sandbox Code Playgroud)
然后,我收到消息:
Direct plonk of unnamed RHS, no copy.
Run Code Online (Sandbox Code Playgroud)
据我所知,RHS 在第一种情况下已被复制,这意味着它正在复制(浅/深,我不知道).如果是这样,为什么会发生这种情况?
即使不是,为什么两个内部通过引用分配的变化呢?有任何想法吗?
在撰写这篇文章时,我想出了我脑海中的主要基本问题(似乎已经忘记了!):分配为"效率低" dt.out[, count := dt[, .N, by=a][["N"]]](与第二种方式相比)?
更新:表达式,
DT[, c(..., lapply(.SD, .), ..., by=.]
Run Code Online (Sandbox Code Playgroud)
已在v1.9.3(FR#2722)的提交#1242内部进行了优化.这是NEWS的条目:
o
DT[, c(..., lapply(.SD, fun)), by=grp]现在优化表单的复杂j表达式,只要.SD它只出现在表单中即可lapply(.SD, fun).例如:
DT[, c(.I, lapply(.SD, sum), mean(x), lapply(.SD, log)), by=grp]
优化为:DT[, list(.I, x=sum(x), y=sum(y), ..., mean(x), log(x), log(y), ...), by=grp]但是
DT[, c(.SD, lapply(.SD, sum)), by=grp],例如尚未优化.这部分解决了FR #2722.感谢Sam Steingold提交FR.
它所说的NAMED vector意味着在C级的内部R意义上; 即,对象是否已被赋予符号并被称为某种东西,而不是原子向量是否具有"names"属性.的NAMED在SEXP结构值取值0,1或2.R使用该知道它是否需要时复制subassign与否.参见R-ints的第1.1.2节.
更好的是,如果jin的优化data.table可以处理:
DT[, c(lapply(.SD,sum),.N), by=a]
Run Code Online (Sandbox Code Playgroud)
这可行但可能很慢.目前只优化了更简单的表单:
DT[, lapply(.SD,sum), by=a]
Run Code Online (Sandbox Code Playgroud)
要回答主要问题,请回答以下问题:
Direct plonk of unnamed RHS, no copy.
Run Code Online (Sandbox Code Playgroud)
与以下相比是可取的:
RHS for item 1 has been duplicated. Either NAMED vector or recycled list RHS.
Run Code Online (Sandbox Code Playgroud)
另一种实现此目的的方法是:
dt.out[, count := dt[, .N, by=a]$N]
Run Code Online (Sandbox Code Playgroud)
我不太清楚为什么[["N"]]返回一个NAM(2)相比$N没有.