【发布时间】:2023-03-14 10:04:01
【问题描述】:
看起来很简单,但是……嗯……
给定一个正则表达式的命名向量和一个数据表如下:
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
我对@987654323@ 中第一个元素的目标是:
如果V1=="a" 设置V3:=2。除非V2 匹配相应的正则表达式^A$,然后是V3:=3。
(a 是names(regexes)[1],^A$ 是regexes[1],2 和3 仅用于演示目的。我还有更多的名称和正则表达式要循环,数据集是大约 300.000 行。)
所以预期的输出是
# V1 V2 V3
# 1: a A 3 (*)
# 2: a B 2 (**)
# 3: b A 1
(*) 3 因为V1 是a 而V2 (A) 匹配正则表达式,
(**) 2 因为V1 是a 而V2 (B) 不匹配^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。
提前致谢!
【问题讨论】:
-
dt[condition, blah := boo]返回修改后的 fulldt(你可以通过在末尾添加额外的空[]来检查) - 因此你得到的结果。将额外条件添加到第二组[]。 -
我试过了,@eddi,但是当我使用
V1==names(regexes)[x] & grepl(regexes[x], V2)作为条件时(即在所有V2s 上匹配每个正则表达式),大约需要 35 秒,而数据框示例需要〜3。所以我认为这显然不是这里的路。 -
这似乎有些可疑。您能否添加一个可以看到减速的更大示例?
-
对我来说这听起来很合理。尽管 data.table 可能会自动为
V1构建索引,但grepl仍然会在 300.000 行上运行多次,而不是像在数据框示例中那样运行在 200 到 2000 行的几个子集上。仍然认为一个更大的例子在这里会有所帮助吗?在那种情况下,我可以尝试建造一个人造的。 -
好的,明白了,你是对的,不需要举例
标签: r for-loop data.table