从 V 1.9.4 开始,data.table 已优化为在 %in% 上使用二元连接,以防数据集已被键入。所以@Richards 的答案应该与最新的data.table 版本具有相同的性能(顺便说一句,%in% 在使用datatable.auto.index = TRUE 时有一个错误,所以请确保你安装了data.table v 1.9.6+会用)
下面是data.table在使用%in%函数时使用二元连接的示意图
require(data.table)
set.seed(123)
dt <- data.table ( a = sample(letters, 25, replace = T),
b = sample(50:100, 25, replace = F))
dtv <- data.table( vowel = c( 'a','e','i','o','u') )
setkey(dt, a)
options(datatable.verbose = TRUE)
dt[a %in% dtv$vowel]
# Starting bmerge ...done in 0 secs <~~~ binary join was triggered
# a b
# 1: i 87
# 2: o 84
# 3: o 62
# 4: u 77
无论哪种方式,您都快到了,您可以在加入时轻松修改c
dt[, c := 'consonant']
dt[dtv, c := 'vowel']
或者,如果您想避免从 dtv 加入不必要的列(如果它们存在),您可以只加入 dtv 中的第一列
dt[dtv$vowel, c := 'consonant']
请注意,我没有使用 .() 或 J()。如果ith 元素不是integer 或numeric 类型,data.table 将默认执行二进制连接而不是行索引。例如,如果您想对列b(类型为integer)执行二元连接,这很重要。比较
setkey(dt, b)
dt[80:85]
# a b <~~~ binary join wan't triggered, instead an attempt to subset by rows 80:85 was made
# 1: NA NA
# 2: NA NA
# 3: NA NA
# 4: NA NA
# 5: NA NA
# 6: NA NA
和
dt[.(80:85)] # or dt[J(80:85)]
# Starting bmerge ...done in 0 secs <~~~ binary join was triggered
# a b
# 1: x 80
# 2: x 81
# 3: NA 82
# 4: NA 83
# 5: o 84
# 6: NA 85
这两种方法的另一个区别是%in%不会返回不匹配的实例,比较一下
setkey(dt, a)
dt[a %in% dtv$vowel]
# Starting bmerge ...done in 0 secs
# a b
# 1: i 87
# 2: o 84
# 3: o 62
# 4: u 77
和
dt[dtv$vowel]
# Starting bmerge ...done in 0 secs
# a b
# 1: a NA <~~~ unmatched values returned
# 2: e NA <~~~ unmatched values returned
# 3: i 87
# 4: o 84
# 5: o 62
# 6: u 77
对于这种特定情况,这无关紧要,因为:= 不会修改不匹配的值,但您可以在其他情况下使用nomatch = 0L
dt[dtv$vowel, nomatch = 0L]
# Starting bmerge ...done in 0 secs
# a b
# 1: i 87
# 2: o 84
# 3: o 62
# 4: u 77
如果您不希望 data.table 如此冗长,请不要忘记设置 options(datatable.verbose = FALSE)。