根据在该表的聚合形式上计算的一些标准,筛选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)]