仅当组中存在给定行时,数据表才对组应用过滤器

datatable apply filter on groups only if a given row exists in the group

我试图仅在特定值存在时才对 datatable 中的组应用过滤器。如果不存在,则过滤器不适用,并且保留该组的所有行。类似于

我正在寻找 答案的数据 table 版本,如果可能的话,但有一些额外的标准。

首先,我尝试了以下方法:

test <- data.table(grp=c(1,1,1,10,10,10,12,12), c=c("a", "b", "c", "b", "c", "c","a","b"))
test[test[, .I[c=="a" | all(c!="a")], by = grp]$V1]

欢迎提出改进建议。

我试图合并的其他标准是检查 grp 是否属于另一个列表。如果属于列表,则适用过滤器

lst <- c("1", "8")
test[test[, .I[(c=="a" & grp %in% lst) | all(c!="a")], by = grp]$V1]

此处,过滤器仅适用于 grp 值 1 而不适用于 12,因为它在 lst 中不存在。它没有返回所有 grp 值为 12 的行,而是完全删除它们。显然,这是错误的,我想知道如何合并条件。

预期结果:

   grp c
1:   1 a
2:  10 b
3:  10 c
4:  10 c
5:  12 a
6:  12 b

对于 grp=1,它存在于 lst 中,因此应用了过滤器。 对于 grp=10,不需要过滤器,因为没有一行带有 c="a" 对于 grp=12,filter 是适用的,但因为它不属于 lst,所以不使用 filter。

谢谢

这是一个使用辅助列的解决方案:

> test <- data.table(grp=c(1,1,1,10,10,10,12,12), c=c("a", "b", "c", "b", "c", "c","a","b"))
> lst <- c(1, 8)
> dtFiltered <- test[, filtera := !all(c != "a") & (grp %in% lst), by = grp][!filtera | c == "a"][, filtera := NULL]

这是使用相同逻辑的一种方法。除了 OP 的逻辑之外,将 OR (|) 条件添加到 return 组中未包含在 'lst' 对象

中的所有行
test[test[, all(c != 'a')| (c == 'a' & .BY %in% lst)|
          !.BY %in% lst, by = grp]$V1]

-输出

#  grp c
#1:   1 a
#2:  10 b
#3:  10 c
#4:  10 c
#5:  12 a
#6:  12 b

或者我们可以使用 if/else 条件

test[test[, .I[if(!.BY %in% lst) TRUE else
     (c=="a" & grp %in% lst) | all(c!="a")] , by = grp]$V1]