r data.table:在for循环

时间:2016-06-28 19:37:40

标签: r for-loop data.table

似乎很容易,但......好吧......

给定正则表达式的命名向量和数据表,如下所示:

library(data.table)
regexes <- c(a="^A$") 
dt <- fread("
a,A,1
a,B,1
b,A,1
")

输入数据表是

dt
#    V1 V2 V3
# 1:  a  A  1
# 2:  a  B  1
# 3:  b  A  1

regexes中第一个元素的目标是:

如果V1=="a"设置V3:=2。除V2与相应的正则表达式^A$匹配,然后V3:=3时。

anames(regexes)[1]^A$regexes[1]23仅用于演示目的。我还有更多名字和循环的正则表达式,数据集大约是300.000行。)

所以预期输出

#    V1 V2 V3
# 1:  a  A  3 (*)
# 2:  a  B  2 (**)
# 3:  b  A  1

(*)3因为V1aV2A)与正则表达式匹配, (**)2因为V1aV2B)与^A$不匹配。

我尝试循环遍历正则表达式并通过这样管道子集:

for (x in seq(regexes)) 
  dt[V1==names(regexes)[x], V3:=2][grepl(regexes[x], V2), V3:=3]

然而......

dt
#    V1 V2 V3
# 1:  a  A  3 
# 2:  a  B  2
# 3:  b  A  3 <- wrong, should remain 2

...它无法按预期工作,grepl使用完整的V2列,而不仅仅是V1=="a"子集。我也尝试过其他一些有用的东西,但是花了太长时间(即不是使用data.table的方式)。

问题:什么是最好的数据表方式?我使用packageVersion("data.table") ‘1.9.7’

请注意,我可以使用数据框路线,例如像这样

df <- as.data.frame(dt)
for (x in seq(regexes)) {
  idx <- df$V1==names(regexes)[x]
  df$V3[idx] <- 2
  df$V3[idx][grepl(regexes[x], df$V2[idx])] <- 3 # or ifelse()
}  

但是 - 当然 - 我不希望将data.table转换为data.frame,然后在可能的情况下返回data.table。

提前致谢!

1 个答案:

答案 0 :(得分:3)

  

...它无法按预期运行,grepl使用完整的V2列,而不仅仅是V1=="a"子集。

我会使用stringi,它允许简单地矢量化正则表达式测试:

library(stringi)
dt[V1 %in% names(regexes), 
  V3 := V3 + 1L + stri_detect(V2, regex = regexes[V1])
]

   V1 V2 V3
1:  a  A  3
2:  a  B  2
3:  b  A  1

stri_detect系列函数类似于基础的grepl