r-根据聚合值筛选数据表的最有效方法



根据在该表的聚合形式上计算的一些标准,筛选data.table的推荐/"最佳"方式(wrt性能(是什么。

一个reprex能说出1000多个单词:

library(data.table)
DT <- data.table(grp = rep(LETTERS[1:3], each = 3), x = 1:9)
setkey(DT, "grp")
DT[DT[, .(nok = any(x == 4)), by = grp][nok == FALSE]]
DT[DT[, .GRP[all(x != 4)], by = grp]]

我可以立即想到这两种解决方案,我的直觉告诉我第二种形式应该"更好"(存储较小的中间表,我不需要将结果连锁(,但我想知道是否有这样做的规范形式?

也许我一开始不需要使用联接,可以对i参数使用分组过滤器?

这显然没有按预期工作(by显然只对j有影响(:

DT[all(x != 4), by = grp]

虽然SO的回答显示了另一种方法,但我主要关心的是性能。因此,如果我想进一步处理过滤后的数据.table(即在过滤后的结果上使用另一个j表达式(,我想知道这些选项中的哪一个通常可以很好地扩展到大表

在我的真实场景中,我有大约1600万行,大约4万个唯一键和14列。

因此,基准数据集可以如下所示:

bench <- data.table(keys = rep(paste0("k", 1:40000), 400))
bench[, paste0("cols", 1:13) := replicate(13, sample(40000 * 400, TRUE), 
simplify = FALSE)]

虽然我正在寻找一个通用答案(如果可能的话(,而不考虑最终选择的过滤器,但实际的过滤器将是找出哪些组包含任何NA值。

我从这个帖子中学到了

你可以这样做。

DT[DT[,.I[all(x!=4)],by=.(grp)]$V1,]

我不认为有一种通用的方法适用于所有情况。它取决于数据集的特性以及过滤标准。数据集可能有多个小组或整数键,而过滤可以使用更快的低级编程方法来实现。

以下是关于您的实际问题的几个选项(即筛选其中一列中具有NA的组(:

DT_keys <- copy(DT)
system.time(setkey(DT_keys, keys))
#   user  system elapsed 
#   1.50    0.67    1.32 
DT_cols1 <- copy(DT)
system.time(setkey(DT_cols1, cols1))
#   user  system elapsed 
#   4.21    0.21    1.30 
microbenchmark::microbenchmark(times=1L,
m0 = DT_keys[, keys[is.na(cols1)], keys]$keys,
m1 = DT_keys[, if (anyNA(cols1)) keys, keys]$keys,
m2 = DT_cols1[.(NA_integer_)]$keys
)

1600万行伪数据的定时:

Unit: milliseconds
expr       min        lq      mean    median        uq       max neval
m0 90.675005 90.675005 90.675005 90.675005 90.675005 90.675005     1
m1 56.548620 56.548620 56.548620 56.548620 56.548620 56.548620     1
m2  4.010301  4.010301  4.010301  4.010301  4.010301  4.010301     1

对于实际数据集的大小来说,时间安排非常快。除非你运行数百次过滤,否则不会节省太多的时间。也许您可能想在运行时之外保存一些其他类型的计时。

数据:

library(data.table)
set.seed(0L)
nk <- 4e4L
nn <- 400L
DT <- data.table(keys = rep(paste0("k", 1L:nk), nn))
DT[, paste0("cols", 1L:13L) := 
replicate(13L, sample(c(NA_integer_, 1L:nk), nk * nn, TRUE), simplify = FALSE)]

最新更新