R: Fast Subsetting Large Data Table 以其中一列中的关键词为条件

R: Fast Subsetting Large Data Table Conditioned on Key Words in One of the Columns

我正在处理的数据table是这样的

require(data.table)
set.seed(2)
dt <- data.table(user=c(rep('a', 3), rep('b', 2), rep('c', 4)),
                 type=c(sample(LETTERS[1:4], 3), 
                        sample(LETTERS[1:4], 2),
                        sample(LETTERS[1:4], 4))
                 )

也就是

   user type
1:    a    A
2:    a    C
3:    a    B
4:    b    A
5:    b    C
6:    c    D
7:    c    A
8:    c    B
9:    c    C     

我只想查找 ABC 类型的特定用户。在上面的示例中,用户 c 不合格,因为他的一个类型记录中有 D。所以期望的输出应该是

   user type
1:    a    A
2:    a    C
3:    a    B
4:    b    A
5:    b    C

我想到的第一种方法,显然效率低下,将dt拆分为split(dt, dt$user),然后检查greplnrow是否相同,然后通过索引和 rbindlist。由于我实际使用的数据 table 有 10989251 行,因此需要一种有效的子集化方法。

按'user'分组,ifall'type'中的元素只有前三个LETTERS,我们得到[=22的子集=](.SD)。在这里,我使用 %chin% 进行向量比较,因为它是针对 character 向量优化的 %in% 的更快版本。

dt[, if(all(type %chin% LETTERS[1:3])) .SD, by = user]
#    user type
#1:    a    A
#2:    a    C
#3:    a    B
#4:    b    A
#5:    b    C

使用经典滤镜选择:

dt[unlist(by(type, user, function(x) !!cumprod(x %in% LETTERS[1:3]))),]
#   user type
#1:    a    A
#2:    a    C
#3:    a    B
#4:    b    A
#5:    b    C

有些人可能会觉得这种方式不那么优雅,但它可能会更快:找到类型为 D 的用户,然后将其排除。如果没有或很少有重复的用户类型对,可以跳过唯一。

badusers = dt[type=='D',unique(user)];
dt.ABCs = dt[!user %in% badusers,];