按照组的数量筛选data.table

4

假设我有一个像这样的data.table

sample<-data.table(id=c(1,1,2,2,3,3,3,4,4),
                   name=c("apple","apple","orange","orange",
                          "pear","pear","pear","banana","banana"),
               atr=c("pretty","ugly","bruised","delicious",
                     "pear-shaped","bruised","infested",
                     "too-ripe","perfect"),
               N=c(10,9,15,4,5,7,7,4,12))

我希望返回基本上独特的unique(sample[,list(id, name)]),但我还想要具有最大N值的atr列的值。在最高N值存在平局的情况下,我不关心选择哪个,但只想选择一个。
这个几乎可以工作:merge(sample[,list(N=max(N)),by=list(id,name1)], sample,by=c("id","name1","N")),但由于pear有两个atr值与最大值相等,因此会返回两个pear。除了没有给出预期结果之外,我还假设/希望有一种方法可以不涉及连接来完成这个问题。
2个回答

4
你可以使用atr[N == max(N)][1]在出现平局的情况下仅返回第一个结果,像这样 -
library(data.table)

sample[, .(atr = atr[N == max(N)][1]), by = .(id, name)]
#    id   name     atr
# 1:  1  apple  pretty
# 2:  2 orange bruised
# 3:  3   pear bruised
# 4:  4 banana perfect

注意: 正如Frank指出的那样,atr[N == max(N)][1] 也可以简化为 atr[which.max(N)]


这只是作为参考,因为我最近也需要做类似的事情,但如果您想以更复杂的方式处理平局情况,您可能需要做类似于 sample[,{x<-atr[N==max(N)]; if(length(x)>1) x else *case of tie action*},by=.(id,name)] 的操作。 - MichaelChirico
2
你可以用 which.max 获取第一个匹配项,对吧?atr = atr[which.max(N)] - Frank
1
@Frank - 是的,完全正确。那就是我昨晚想不起来的函数!干杯 - Rich Scriven

3

我会使用 order

> unique(sample[order(-N), .(id, name, atr)], by = c("id", "name"))
   id   name     atr
1:  2 orange bruised
2:  4 banana perfect
3:  1  apple  pretty
4:  3   pear bruised

如果您想保持整体排序,只需使用order(id, name, -N)即可。
您也可以将此分为两行:
setorder(sample, -N) #done by reference, as with all set* functions in data.table
unique(sample[ , .(id, name, atr)], by = c("id", "name"))

也许更好的选择是根据你的最终目标而定:
setkey(setorder(sample, -N), id, name)
unique(sample[ , .(id, name, atr)])

(注意:最后一点很重要,因为先使用setorder将覆盖键设置为NULL
注:请勿解释,保留HTML标记。

我不知道 unique 接受 by。同时,我也很惊讶这个方法比 Richard 的更快。尽管实际数据集中只有 0.001 和 0.005 秒的差异,所以它并没有任何真正的实际影响。 - Dean MacGregor
@DeanMacGregor 是的,如果a)您想在使用“unique”时保持原始“data.table”的键不变,并且b)如果您只想对“data.table”的某些键进行“unique”,则“by”参数特别有用。 - MichaelChirico
让我希望在头部和尾部有一个按参数来的函数。 - Clayton Stanley
@ClaytonStanley head(dt[,.SD[1],by=keys]) - MichaelChirico
我在思考 head(dt, 1, by=keys)。 - Clayton Stanley
@ClaytonStanley 那段代码的作用就是这样;当然,如果你希望将其构建到 head/tail 函数中,我们鼓励你提交一个功能请求 - MichaelChirico

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