查找字符串列表的每个元素与 R 中向量的每个字符串之间的匹配项(避免 'for')
Finding matches between each element of a list of strings and each string of a vector in R (avoiding 'for')
我在数据框中有两列要比较的字符串。第一个是字符串向量,第二个是一个列表,每个元素中都有一个迷你字符串向量。想象一下有这样一个数据框:
V L
"Anameone" "name" "asd"
"Bnametwo" "dfg"
"Cnamethree" "hey" "C" "hi"
我想看看L的第一个元素中的某些词是否出现在V的第一个元素中,L的第二个元素中的某些词是否出现在V的第二个元素中...等等。
我可以用这样的循环做我想做的事:
for (i in c(1:3)){
df$matches[i] <- any(df$L[[i]],grepl, df$V[i],ignore.case = T))
}
所以输出是:
> df$matches
[1] "TRUE" "FALSE" "TRUE"
但实际上我有大约 100.000 行而不是 3 行,这确实花费了太长时间。我一直无法弄清楚如何更有效地做到这一点,有什么想法吗?在这个例子中,我所有其他不使用索引的尝试都以矩阵 3x3 结束,因为它比较 "all with all",我认为这可能比 for.
更糟糕。
应用应该有效:
df<-data.frame(V=c("Anameone","Bnametwo","Cnamethree"),
L=I(list(c("name","asd"),"dfg",c("hey","C","hi"))))
sapply(as.character(df$V),function(x)
{grepl(paste(unlist(df$L[1]),collapse="|"),x)})
您必须检查它是否比使用 for 循环更快。我无法重新创建您的示例。
您可以使用 purrr::map2_lgl()
to iterate over both columns, testing if each element of l
is in v
with stringr::str_detect()
,然后使用 any()
得到 TRUE
或 FALSE
如果有任何匹配项。
library(dplyr)
library(purrr)
library(stringr)
df <- tibble(
v = c("Anameone", "Bnametwo", "Cnamethree"),
l = list(c("name", "asd"), "dfg", c("hey", "C", "hi"))
)
mutate(df, matches = map2_lgl(v, l, ~ str_detect(.x, .y) %>% any()))
#> # A tibble: 3 x 3
#> v l matches
#> <chr> <list> <lgl>
#> 1 Anameone <chr [2]> TRUE
#> 2 Bnametwo <chr [1]> FALSE
#> 3 Cnamethree <chr [3]> TRUE
是这样的吗?
df <- data.frame(V = c('Anameone','Bnametwo','Cnamethree'),
L = I(list(c('name','asd'),c('dfg'),c('hey','C','hi'))))
sapply(1:nrow(df), function(x) any(sapply(df$L[[x]], function(y) grepl(y, df$V[x]))))
# [1] TRUE FALSE TRUE
我在数据框中有两列要比较的字符串。第一个是字符串向量,第二个是一个列表,每个元素中都有一个迷你字符串向量。想象一下有这样一个数据框:
V L
"Anameone" "name" "asd"
"Bnametwo" "dfg"
"Cnamethree" "hey" "C" "hi"
我想看看L的第一个元素中的某些词是否出现在V的第一个元素中,L的第二个元素中的某些词是否出现在V的第二个元素中...等等。
我可以用这样的循环做我想做的事:
for (i in c(1:3)){
df$matches[i] <- any(df$L[[i]],grepl, df$V[i],ignore.case = T))
}
所以输出是:
> df$matches
[1] "TRUE" "FALSE" "TRUE"
但实际上我有大约 100.000 行而不是 3 行,这确实花费了太长时间。我一直无法弄清楚如何更有效地做到这一点,有什么想法吗?在这个例子中,我所有其他不使用索引的尝试都以矩阵 3x3 结束,因为它比较 "all with all",我认为这可能比 for.
更糟糕。应用应该有效:
df<-data.frame(V=c("Anameone","Bnametwo","Cnamethree"),
L=I(list(c("name","asd"),"dfg",c("hey","C","hi"))))
sapply(as.character(df$V),function(x)
{grepl(paste(unlist(df$L[1]),collapse="|"),x)})
您必须检查它是否比使用 for 循环更快。我无法重新创建您的示例。
您可以使用 purrr::map2_lgl()
to iterate over both columns, testing if each element of l
is in v
with stringr::str_detect()
,然后使用 any()
得到 TRUE
或 FALSE
如果有任何匹配项。
library(dplyr)
library(purrr)
library(stringr)
df <- tibble(
v = c("Anameone", "Bnametwo", "Cnamethree"),
l = list(c("name", "asd"), "dfg", c("hey", "C", "hi"))
)
mutate(df, matches = map2_lgl(v, l, ~ str_detect(.x, .y) %>% any()))
#> # A tibble: 3 x 3
#> v l matches
#> <chr> <list> <lgl>
#> 1 Anameone <chr [2]> TRUE
#> 2 Bnametwo <chr [1]> FALSE
#> 3 Cnamethree <chr [3]> TRUE
是这样的吗?
df <- data.frame(V = c('Anameone','Bnametwo','Cnamethree'),
L = I(list(c('name','asd'),c('dfg'),c('hey','C','hi'))))
sapply(1:nrow(df), function(x) any(sapply(df$L[[x]], function(y) grepl(y, df$V[x]))))
# [1] TRUE FALSE TRUE