使用data.table按组筛选最大值对应的行

72

假设我有一个包含一些棒球运动员的data.table:

library(plyr)
library(data.table)

bdt <- as.data.table(baseball)

对于每个组(由玩家“id”给出),我想选择与最大游戏数“g”相对应的行。在plyr中,这很简单:

对于每个由玩家"id"指定的分组,我想选择与最大游戏数"g"相对应的行。这在plyr中很容易实现:

ddply(baseball, "id", subset, g == max(g))

使用 data.table 的等价代码是什么?

我尝试过:

setkey(bdt, "id") 
bdt[g == max(g)]  # only one row
bdt[g == max(g), by = id]  # Error: 'by' or 'keyby' is supplied but not j
bdt[, .SD[g == max(g)]] # only one row

这有效:

bdt[, .SD[g == max(g)], by = id] 

但它只比plyr快30%,这表明它可能不符合惯用方式。


2
哇,那真的很慢,但如果你用“year”代替“.SD”……我得到了年、.SD、plyr分别为0.01、1.58、2.39用户时间。 - Frank
@Frank,但我想要整个数据框,而不仅仅是年份。我会澄清问题。 - hadley
1个回答

92

这是快速的 data.table 方法:

bdt[bdt[, .I[g == max(g)], by = id]$V1]

这样可以避免构造.SD,而这是您的表达式中的瓶颈。

编辑:实际上,OP运行缓慢的主要原因不仅仅是其中有.SD,而是它以特定方式使用它 - 通过调用[.data.table,目前它的开销很大,所以在一个循环中运行它(当使用by时)会累积非常大的惩罚。


5
我猜测Hadley想要以编程方式实现这个目标,这种情况下他需要使用这个语法:bdt[bdt[, .I[g == max(g)], by = id][,V1]],对吗? - joran
2
@joran 我正在手动构建调用,所以这并不重要。 - hadley
6
最终原始方法将被优化。请参见FR 2330,对.SD[i]查询进行优化,保持优雅但使其更快,而不改变其原意。 - mnel
3
该问题链接已经从R-Forge转移到GitHub,链接地址为#613 - Matt Dowle
如果我在内框架中添加verbose = TRUE,我会看到GForce FALSE,但它仍然比类似于bdt[bdt[, .(g=max(g)), by=id], on=c("id","g")]的更快,虽然我不知道这是否总是情况。 - Alexis

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