数据表 - 在组内选择前n行

34

虽然很简单,但我不知道如何在数据表中使用 data.table 选择每个组中的前 n 行。你能帮我吗?


这非常接近于:https://dev59.com/hWLVa4cB1Zd3GeqPxpRy - MichaelChirico
2个回答

71

作为替代方案:

dt[, .SD[1:3], cyl]

当您查看示例数据集中的速度时,head方法与@eddi的.I方法相当。与microbenchmark包进行比较:
microbenchmark(head = dt[, head(.SD, 3), cyl],
               SD = dt[, .SD[1:3], cyl], 
               I = dt[dt[, .I[1:3], cyl]$V1],
               times = 10, unit = "relative")

结果为:

Unit: relative
 expr      min       lq     mean   median       uq       max neval cld
 head 1.000000 1.000000 1.000000 1.000000 1.000000 1.0000000    10  a 
   SD 2.156562 2.319538 2.306065 2.365190 2.318540 2.1908401    10   b
    I 1.001810 1.029511 1.007371 1.018514 1.016583 0.9442973    10  a 

然而,data.table 是专为大型数据集设计的。因此,再次运行此比较:
# creating a 30 million dataset
largeDT <- dt[,.SD[sample(.N, 1e7, replace = TRUE)], cyl]
# running the benchmark on the large dataset
microbenchmark(head = largeDT[, head(.SD, 3), cyl],
               SD = largeDT[, .SD[1:3], cyl], 
               I = largeDT[largeDT[, .I[1:3], cyl]$V1],
               times = 10, unit = "relative")

结果为:

Unit: relative
 expr      min       lq     mean   median       uq     max neval cld
 head 2.279753 2.194702 2.221330 2.177774 2.276986 2.33876    10   b
   SD 2.060959 2.187486 2.312009 2.236548 2.568240 2.55462    10   b
    I 1.000000 1.000000 1.000000 1.000000 1.000000 1.00000    10  a 

现在,.I 方法显然是最快的方法。

更新于2016年02月12日:

使用最新版本的data.table包,.I方法仍然是最快的。无论是.SD方法还是head()方法似乎取决于数据集的大小。现在基准测试结果如下:

Unit: relative
 expr      min       lq     mean   median       uq      max neval cld
 head 2.093240 3.166974 3.473216 3.771612 4.136458 3.052213    10   b
   SD 1.840916 1.939864 2.658159 2.786055 3.112038 3.411113    10   b
    I 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10  a 

然而,如果数据集稍微小一些(但仍然相当大),情况会有所改变:

largeDT2 <- dt[,.SD[sample(.N, 1e6, replace = TRUE)], cyl]

现在基准略微偏向于使用head方法而非.SD方法:
Unit: relative
 expr      min       lq     mean   median       uq      max neval cld
 head 1.808732 1.917790 2.087754 1.902117 2.340030 2.441812    10   b
   SD 1.923151 1.937828 2.150168 2.040428 2.413649 2.436297    10   b
    I 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10  a 

这是用1.9.7完成的吗?我知道最近对.SD的一些操作进行了优化... - MichaelChirico
@MichaelChirico 是的,但我正在使用相对较旧的1.9.7版本(在“rowid”引入后不久)。所以,这取决于最近是多久之前;-) - Jaap
我认为相关的提交是在11月初左右。 - MichaelChirico
1
性能可能取决于 cyl 的基数。 - jangorecki
1
@Jaap 感谢再次测试。我用 setDTthreads(1) 进行了测试,但仍然没有找到你的结果。我认为 @jangorecki 是正确的,结果高度依赖于分组变量的基数。当基数小于 6 时,.I 对我来说更快,但在其他情况下,.SD 和 head 更快。 - Samuel Allain
显示剩余3条评论

19
我们可以使用.SDhead
library(data.table)

dt <- data.table(mtcars)

> dt[, head(.SD, 3), by = "cyl"]

   cyl  mpg  disp  hp drat    wt  qsec vs am gear carb
1:   6 21.0 160.0 110 3.90 2.620 16.46  0  1    4    4
2:   6 21.0 160.0 110 3.90 2.875 17.02  0  1    4    4
3:   6 21.4 258.0 110 3.08 3.215 19.44  1  0    3    1
4:   4 22.8 108.0  93 3.85 2.320 18.61  1  1    4    1
5:   4 24.4 146.7  62 3.69 3.190 20.00  1  0    4    2
6:   4 22.8 140.8  95 3.92 3.150 22.90  1  0    4    2
7:   8 18.7 360.0 175 3.15 3.440 17.02  0  0    3    2
8:   8 14.3 360.0 245 3.21 3.570 15.84  0  0    3    4
9:   8 16.4 275.8 180 3.07 4.070 17.40  0  0    3    3

1
请注意,实际上 head.data.table (getAnywhere("head.data.table"))只是调用了比 @Jaap 的答案略微更健壮的版本。 - MichaelChirico

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