为何在data.table中用所有列分组时.SD会生成空表?
关于data.table中by包含所有列时.SD为空表的疑问
我在Stack Overflow的相关评论里看到:当by参数用到所有列时,.SD会变成空的data.table,这个逻辑我搞不懂,举个例子:
library(data.table) dt <- data.table(x = c(1,1,2,2), y = c(1,2,3,3)) dt
输出:
x y 1: 1 1 2: 1 2 3: 2 3 4: 2 3
执行dt[, .SD[.N], by = .(x, y)]得到空表:
Empty data.table (0 rows and 2 cols): x,y
我本来以为这段代码的输出应该和下面这段代码的结果一致:
dt[, keep := (1:.N) == .N, by = .(x, y)] dt[keep == 1, c("x", "y")]
输出:
x y 1: 1 1 2: 1 2 3: 2 3
问题原因与解决方法
为什么会得到空表?
data.table的规则是:.SD代表除了by里的分组列之外的所有列。当你把所有列都设为分组列时,.SD就没剩下其他列能包含了,直接变成空表。这时候.SD[.N]就是从空表里取第N行,结果当然是空的。
怎么拿到你想要的结果?
要是想按所有列分组后保留每组的最后一行,有几种更直接的写法:
用
unique()加fromLast = TRUE,直接去重并留每组最后一行:unique(dt, by = c("x", "y"), fromLast = TRUE)用
.I获取每组最后一行的索引,再提取对应行:dt[dt[, .I[.N], by = .(x, y)]$V1]或者直接在
j里返回分组列的最后一行(毕竟分组列本身就在by里,不用从.SD取):dt[, .(x = last(x), y = last(y)), by = .(x, y)]
这几种写法都能得到你期望的输出。
内容的提问来源于stack exchange,提问作者SimonSimon
相关产品推荐
相关产品推荐

